Module Widefield-Imaging-Acquisition.gui.interface

Expand source code
import sys
import time
import os
import matplotlib.pyplot as plt
from PyQt5.QtCore import QModelIndex, Qt, QLocale, qInstallMessageHandler
import numpy as np
from PyQt5.QtWidgets import (
    QVBoxLayout,
    QWidget,
    QGridLayout,
    QLabel,
    QHBoxLayout,
    QLineEdit,
    QCheckBox,
    QPushButton,
    QStackedLayout,
    QComboBox,
    QMessageBox,
    QFileDialog,
    QApplication,
    QSlider,
    QHeaderView,
    QDialog,
    QWizard,
)
from PyQt5.QtGui import (
    QIntValidator,
    QDoubleValidator,
    QFont,
    QIcon,
    QBrush,
    QColor,
    QPixmap,
)
from matplotlib.widgets import RectangleSelector
from threading import Thread

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from src.controls import DAQ, Instrument, Camera
from src.blocks import Experiment
from src.tree import Tree
from src.plot import PlotWindow
from src.calculations import (
    get_dictionary,
    shrink_array,
    frames_acquired_from_camera_signal,
    get_baseline_frame_indices,
    average_baseline,
)
import warnings

warnings.filterwarnings("ignore")


class App(QWidget):
    def __init__(self):
        """Initialize the application"""
        super().__init__()
        qInstallMessageHandler(self.handler)
        self.cwd = os.path.dirname(os.path.dirname(__file__))
        self.config = get_dictionary(os.path.join(self.cwd, "config.json"))
        self.ports = self.config["Ports"]
        self.elapsed_time = 0
        self.files_saved = False
        self.save_files_after_stop = False
        self.roi_extent = None
        self.max_exposure = 4096
        self.slider_values = {
            "Infrared": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
            "Red": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
            "Green": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
            "Blue": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
        }
        self.daq_generated = False
        self.onlyFloat = QDoubleValidator()
        self.onlyFloat.setLocale(QLocale(QLocale.English, QLocale.UnitedStates))
        self.onlyFloat.setNotation(QDoubleValidator.StandardNotation)
        self.onlyFramerate = QIntValidator(1, 57, self)
        self.onlyExposure = QIntValidator(1, 900, self)
        self.start_container = QWidget()
        self.start_layout = QVBoxLayout()
        self.start_container.setLayout(self.start_layout)
        self.start_title = QLabel("Welcome to WideBrain!")
        self.start_title.setFont(QFont("IBM Plex Sans", 20, QFont.Bold))
        self.start_title.setAlignment(Qt.AlignCenter)
        self.start_image = QLabel()
        self.start_image.setPixmap(
            QPixmap(os.path.join(self.cwd, "assets", "logo-small.png"))
        )
        self.start_image.setAlignment(Qt.AlignCenter)
        self.start_description = QLabel("Choose the type of experiment you want to run")
        self.start_description.setFont(QFont("IBM Plex Sans", 14, QFont.Light))
        self.start_description.setWordWrap(True)
        self.start_description.setAlignment(Qt.AlignCenter)

        self.trigger_mode_button = QPushButton("Start in Trigger Mode")
        self.trigger_mode_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "bolt.png"))
        )
        self.trigger_mode_button.setFont(QFont("IBM Plex Sans", 15, QFont.Light))
        self.trigger_mode_button.clicked.connect(self.start_in_trigger_mode)

        self.acquisition_mode_button = QPushButton("Start in Acquisition Mode")
        self.acquisition_mode_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "camera.png"))
        )
        self.acquisition_mode_button.setFont(QFont("IBM Plex Sans", 15, QFont.Light))
        self.acquisition_mode_button.clicked.connect(self.start_in_acquisition_mode)

        self.start_buttons = QHBoxLayout()
        self.start_buttons.addWidget(self.trigger_mode_button)
        self.start_buttons.addWidget(self.acquisition_mode_button)

        self.start_layout.addWidget(self.start_title)
        self.start_layout.addWidget(self.start_image)
        self.start_layout.addWidget(self.start_description)
        self.start_layout.addLayout(self.start_buttons)

        self.grid_layout = QGridLayout()
        self.grid_layout.addWidget(self.start_container, 0, 0)

        self.setLayout(self.grid_layout)
        self.show()

    def start_in_trigger_mode(self):
        """Initialize the interface in trigger mode"""
        self.start_container.setParent(None)
        self.acquisition_mode = False
        self.initUI()

    def start_in_acquisition_mode(self):
        """Initialize the interface in acquisition mode"""
        self.start_container.setParent(None)
        self.acquisition_mode = True
        self.initUI()

    def closeEvent(self, *args, **kwargs):
        """Stop all processes when closing the application"""
        self.video_running = False
        try:
            self.camera.stop_signal = True
            self.camera.video_running = False
            self.daq.stop_signal = True
            self.daq.camera.cam.stop_acquisition()
            print("Program Closed")
        except Exception as err:
            pass
        self.check_if_thread_is_alive()

    def handler(*args, **kwargs):
        """Ignore Qt messages"""
        pass

    def initUI(self):
        """Initialize the user interface"""
        self.title = "Widefield Imaging Aquisition"
        self.dimensions = (10, 10, 640, 480)
        self.setWindowTitle(self.title)
        self.setGeometry(*self.dimensions)

        # self.grid_layout = QGridLayout()
        # self.setLayout(self.grid_layout)
        self.grid_layout.setAlignment(Qt.AlignTop)

        self.experiment_settings_label = QLabel("Experiment Settings")
        self.experiment_settings_label.setFont(QFont("IBM Plex Sans", 17))
        self.grid_layout.addWidget(self.experiment_settings_label, 0, 0)

        self.experiment_settings_main_window = QVBoxLayout()
        self.experiment_name_window = QHBoxLayout()
        self.experiment_name = QLabel("Experiment Name")
        self.experiment_name_window.addWidget(self.experiment_name)
        self.experiment_name_cell = QLineEdit()
        self.experiment_name_window.addWidget(self.experiment_name_cell)
        self.experiment_settings_main_window.addLayout(self.experiment_name_window)

        self.mouse_id_window = QHBoxLayout()
        self.mouse_id_label = QLabel("Mouse ID")
        self.mouse_id_window.addWidget(self.mouse_id_label)
        self.mouse_id_cell = QLineEdit()
        self.mouse_id_window.addWidget(self.mouse_id_cell)
        self.experiment_settings_main_window.addLayout(self.mouse_id_window)

        self.framerate_exposure_window = QHBoxLayout()
        self.exposure_window = QHBoxLayout()
        self.exposure_label = QLabel("Exposure (ms)")
        self.exposure_window.addWidget(self.exposure_label)
        self.exposure_cell = QLineEdit("10")
        self.exposure_cell.setValidator(self.onlyExposure)
        self.exposure_cell.textChanged.connect(self.verify_exposure)
        self.exposure_window.addWidget(self.exposure_cell)
        self.framerate_exposure_window.addLayout(self.exposure_window)
        self.framerate_window = QHBoxLayout()
        self.framerate_label = QLabel("Framerate")
        self.framerate_window.addWidget(self.framerate_label)
        self.framerate_cell = QLineEdit("30")
        self.framerate_cell.setValidator(self.onlyFramerate)
        self.framerate_cell.textChanged.connect(self.verify_exposure)
        self.framerate_window.addWidget(self.framerate_cell)
        self.framerate_exposure_window.addLayout(self.framerate_window)

        if self.acquisition_mode:
            self.experiment_settings_main_window.addLayout(
                self.framerate_exposure_window
            )

        self.exposure_warning_label = QLabel("Invalid Exposure / Frame Rate")
        if self.acquisition_mode:
            self.experiment_settings_main_window.addWidget(self.exposure_warning_label)
        self.exposure_warning_label.setStyleSheet("color: red")
        self.exposure_warning_label.setHidden(True)

        self.directory_window = QHBoxLayout()
        self.directory_save_files_checkbox = QCheckBox()
        self.directory_save_files_checkbox.setText("Save")
        self.directory_save_files_checkbox.stateChanged.connect(self.enable_directory)
        self.directory_window.addWidget(self.directory_save_files_checkbox)
        self.directory_choose_button = QPushButton("Select Directory")
        self.directory_choose_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "folder-plus.png"))
        )
        # self.directory_choose_button.setIcon(QIcon(os.path.join("gui", "icons", "folder-plus.png")))
        self.directory_choose_button.setDisabled(True)
        self.directory_choose_button.clicked.connect(self.choose_directory)
        self.directory_window.addWidget(self.directory_choose_button)
        self.directory_cell = QLineEdit("")
        self.directory_cell.setReadOnly(True)
        self.directory_window.addWidget(self.directory_cell)
        self.experiment_settings_main_window.addLayout(self.directory_window)
        self.trigger_checkbox = QCheckBox("Wait for Trigger")
        self.trigger_activated = False
        self.trigger_checkbox.stateChanged.connect(self.set_trigger)
        # self.experiment_settings_main_window.addWidget(self.trigger_checkbox)

        self.save_config_button = QPushButton("Save Config")
        self.save_config_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "save.png"))
        )
        self.save_config_button.clicked.connect(self.save_config)
        self.save_config_button.setEnabled(False)
        self.experiment_settings_main_window.addWidget(self.save_config_button)

        self.experiment_settings_main_window.addStretch()

        if self.acquisition_mode:
            self.grid_layout.addLayout(self.experiment_settings_main_window, 1, 0)
        else:
            self.grid_layout.addLayout(self.experiment_settings_main_window, 1, 0, 1, 2)

        self.image_settings_label = QLabel("Image Settings")
        self.image_settings_label.setFont(QFont("IBM Plex Sans", 17))
        if self.acquisition_mode:
            self.grid_layout.addWidget(self.image_settings_label, 0, 1)

        self.image_settings_main_window = QVBoxLayout()
        self.image_settings_main_window.setAlignment(Qt.AlignLeft)
        self.image_settings_main_window.setAlignment(Qt.AlignTop)

        self.image_settings_second_window = QHBoxLayout()
        self.ir_checkbox = QCheckBox("Infrared")
        self.ir_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.ir_checkbox)
        self.red_checkbox = QCheckBox("Red")
        self.red_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.red_checkbox)
        self.green_checkbox = QCheckBox("Green")
        self.green_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.green_checkbox)
        self.fluorescence_checkbox = QCheckBox("Blue")
        self.fluorescence_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.fluorescence_checkbox)

        self.light_channel_layout = QHBoxLayout()
        self.preview_light_label = QLabel("Light Channel Preview")
        self.light_channel_layout.addWidget(self.preview_light_label)
        self.preview_light_combo = QComboBox()
        self.preview_light_combo.setEnabled(False)
        self.preview_light_combo.currentIndexChanged.connect(
            self.change_preview_light_channel
        )
        self.light_channel_layout.addWidget(self.preview_light_combo)
        # self.activation_map_checkbox = QCheckBox("Show Activation Map")
        self.activation_map_window = QHBoxLayout()
        self.activation_map_label = QLabel("Activation Map")
        self.activation_map_window.addWidget(self.activation_map_label)
        self.activation_map_combo = QComboBox()
        self.activation_map_combo.addItem("None")
        self.activation_map_combo.addItem("Normal")
        self.activation_map_combo.addItem("Logarithmic")
        self.activation_map_combo.currentIndexChanged.connect(self.adjust_slider)
        self.activation_map_window.addWidget(self.activation_map_combo)

        self.image_settings_main_window.addLayout(self.image_settings_second_window)
        self.image_settings_main_window.addLayout(self.light_channel_layout)
        # self.image_settings_main_window.addWidget(self.activation_map_checkbox)
        self.image_settings_main_window.addLayout(self.activation_map_window)

        self.roi_buttons = QStackedLayout()

        self.roi_layout1 = QHBoxLayout()
        self.roi_layout1.setAlignment(Qt.AlignLeft)
        self.roi_layout1.setAlignment(Qt.AlignTop)
        self.roi_layout1.setContentsMargins(0, 0, 0, 0)
        self.reset_roi_button = QPushButton()
        self.reset_roi_button.setText("Reset ROI")
        self.reset_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-out-area.png"))
        )
        # self.reset_roi_button.setIcon(QIcon("gui/icons/zoom-out-area.png"))
        self.reset_roi_button.setEnabled(False)
        self.reset_roi_button.clicked.connect(self.reset_roi)
        self.roi_layout1.addWidget(self.reset_roi_button)

        self.set_roi_button = QPushButton()
        self.set_roi_button.setText("Set ROI")
        self.set_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-in-area.png"))
        )
        self.set_roi_button.clicked.connect(self.set_roi)
        self.roi_layout1.addWidget(self.set_roi_button)
        self.roi_layout1_container = QWidget()
        self.roi_layout1_container.setLayout(self.roi_layout1)

        self.roi_layout2 = QHBoxLayout()
        self.roi_layout2.setAlignment(Qt.AlignLeft)
        self.roi_layout2.setAlignment(Qt.AlignTop)
        self.roi_layout2.setContentsMargins(0, 0, 0, 0)
        self.cancel_roi_button = QPushButton()
        self.cancel_roi_button.setText("Cancel")
        self.cancel_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-cancel.png"))
        )
        self.cancel_roi_button.clicked.connect(self.cancel_roi)
        self.roi_layout2.addWidget(self.cancel_roi_button)

        self.save_roi_button = QPushButton()
        self.save_roi_button.setText("Save ROI")
        self.save_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-check.png"))
        )
        self.save_roi_button.clicked.connect(self.save_roi)
        self.roi_layout2.addWidget(self.save_roi_button)
        self.roi_layout2_container = QWidget()
        self.roi_layout2_container.setLayout(self.roi_layout2)

        if self.acquisition_mode:
            self.roi_buttons.addWidget(self.roi_layout1_container)
            self.roi_buttons.addWidget(self.roi_layout2_container)
            self.image_settings_main_window.addLayout(self.roi_buttons)

        self.exposure_slider = QSlider(Qt.Horizontal, self)
        self.exposure_slider.setRange(0, 4096)
        self.exposure_slider.setValue(4096)
        self.exposure_slider.valueChanged.connect(self.adjust_exposure)
        self.image_settings_main_window.addWidget(self.exposure_slider)
        self.image_settings_main_window.addStretch()

        self.activate_live_preview_button = QPushButton()
        self.activate_live_preview_button.setText("Start Live Preview")
        self.activate_live_preview_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "video.png"))
        )
        self.activate_live_preview_button.clicked.connect(self.open_live_preview_thread)

        self.deactivate_live_preview_button = QPushButton()
        self.deactivate_live_preview_button.setText("Stop Live Preview")
        self.deactivate_live_preview_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "video-off.png"))
        )
        self.deactivate_live_preview_button.clicked.connect(self.stop_live)

        self.image_settings_main_window.addStretch()

        if self.acquisition_mode:
            self.grid_layout.addLayout(self.image_settings_main_window, 1, 1)

        self.live_preview_label = QLabel("Live Preview")
        self.live_preview_label.setFont(QFont("IBM Plex Sans", 17))
        self.image_view = PlotWindow()
        self.plot_image = plt.imshow(
            np.zeros(
                (int(1024 / self.config["Binning"]), int(1024 / self.config["Binning"]))
            ),
            cmap="binary_r",
            vmin=0,
            vmax=4096,
            origin="lower",
        )
        self.plot_image.axes.get_xaxis().set_visible(False)
        self.plot_image.axes.axes.get_yaxis().set_visible(False)

        if self.acquisition_mode:
            self.grid_layout.addWidget(self.live_preview_label, 0, 2)
            self.grid_layout.addWidget(self.image_view, 1, 2)

        self.tree_label = QLabel("Stimulation Tree")
        self.tree_label.setFont(QFont("IBM Plex Sans", 17))
        self.grid_layout.addWidget(self.tree_label, 2, 0)

        self.tree_window = QVBoxLayout()
        self.tree = Tree()
        self.tree.setHeaderLabels(
            [
                "0 Name",
                "1 Iterations",
                "2 Delay",
                "3 Jitter",
                "4 Type",
                "5 Pulses",
                "6 Duration",
                "7 Jitter",
                "8 Width",
                "9 Frequency",
                "10 Duty",
                "11 Type2",
                "12 Pulses 2",
                "13 Jitter 2",
                "14 Width 2",
                "15 Frequency 2",
                "16 Duty 2",
                "17 Baseline",
                "18 Canal 1",
                "19 Canal 2",
                "20 Valid",
                "21 Heigth",
                "22 Heigth 2",
                "23 Type 3",
                "24 Pulses 3",
                "25 Jitter 3",
                "26 Width 3",
                "27 Frequency 3",
                "28 Duty 3",
                "29 Heigth 3",
                "30 Canal 3",
            ]
        )
        if not self.config["Debug"]:
            for i in range(1, 20):
                self.tree.header().hideSection(i)
            for i in range(21, 31):
                self.tree.header().hideSection(i)
            self.tree.setHeaderHidden(True)
            self.tree.header().setSectionResizeMode(0, QHeaderView.Stretch)
            self.tree.header().setStretchLastSection(False)
        self.tree.currentItemChanged.connect(self.actualize_window)
        self.tree_window.addWidget(self.tree)

        self.tree_switch_window = QStackedLayout()
        self.tree_second_window = QHBoxLayout()
        self.stim_buttons_container = QWidget()
        self.delete_item_button = QPushButton("Delete")
        self.delete_item_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "trash.png"))
        )
        self.delete_item_button.clicked.connect(self.tree.delete_item)
        self.tree_second_window.addWidget(self.delete_item_button)
        self.add_brother_branch_button = QPushButton("Add Sibling")
        self.add_brother_branch_button.clicked.connect(self.tree.add_brother)
        self.add_brother_branch_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "arrow-bar-down.png"))
        )
        self.tree_second_window.addWidget(self.add_brother_branch_button)
        self.add_child_branch_button = QPushButton("Add Child")
        self.add_child_branch_button.clicked.connect(self.tree.add_child)
        self.add_child_branch_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "arrow-bar-right.png"))
        )
        self.tree_second_window.addWidget(self.add_child_branch_button)
        self.stim_buttons_container.setLayout(self.tree_second_window)
        self.tree_switch_window.addWidget(self.stim_buttons_container)

        self.tree_third_window = QHBoxLayout()
        self.import_button = QPushButton("Import Configuration")
        self.import_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "packge-import.png"))
        )
        self.import_button.clicked.connect(self.import_config)
        self.tree_third_window.addWidget(self.import_button)
        self.new_branch_button = QPushButton("New Stimulation")
        self.new_branch_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "square-plus.png"))
        )
        self.tree_third_window.addWidget(self.new_branch_button)
        self.stim_buttons_container2 = QWidget()
        self.stim_buttons_container2.setLayout(self.tree_third_window)
        self.tree_switch_window.addWidget(self.stim_buttons_container2)
        self.new_branch_button.clicked.connect(self.tree.first_stimulation)
        self.grid_layout.addLayout(self.tree_switch_window, 4, 0)

        self.tree_switch_window.setCurrentIndex(1)
        self.grid_layout.addLayout(self.tree_window, 3, 0)

        self.signal_adjust_label = QLabel("Signal Adjust")
        self.signal_adjust_label.setFont(QFont("IBM Plex Sans", 17))
        self.grid_layout.addWidget(self.signal_adjust_label, 2, 1)

        self.signal_adjust_superposed = QStackedLayout()
        self.stimulation_edit_layout = QVBoxLayout()
        self.stimulation_edit_layout.setContentsMargins(0, 0, 0, 0)

        self.canal_window = QVBoxLayout()
        self.canal_window.setAlignment(Qt.AlignLeft)
        self.canal_window.setAlignment(Qt.AlignTop)
        self.canal_window.setContentsMargins(0, 0, 0, 0)

        self.first_canal_check = QCheckBox()
        self.first_canal_check.stateChanged.connect(self.canals_to_tree)
        self.first_canal_check.setText("Canal 1")

        self.stim_type_cell = QComboBox()
        self.stim_type_cell.addItem("square")
        self.stim_type_cell.addItem("random-square")
        self.stim_type_cell.addItem("Third")
        self.stim_type_cell.currentIndexChanged.connect(self.type_to_tree)
        self.stimulation_type_window = QHBoxLayout()
        self.stimulation_type_window.addWidget(self.first_canal_check)
        self.stimulation_type_window.addWidget(self.stim_type_cell)
        self.canal_window.addLayout(self.stimulation_type_window)

        self.different_signals_window = QStackedLayout()
        self.canal_window.addLayout(self.different_signals_window)

        self.second_canal_check = QCheckBox()
        self.second_canal_check.stateChanged.connect(self.canals_to_tree)
        self.second_canal_check.setText("Canal 2")

        self.stim_type_cell2 = QComboBox()
        self.stim_type_cell2.addItem("square")
        self.stim_type_cell2.addItem("random-square")
        self.stim_type_cell2.addItem("Third")
        self.stim_type_cell2.currentIndexChanged.connect(self.type_to_tree)
        self.stimulation_type_window2 = QHBoxLayout()
        self.stimulation_type_window2.addWidget(self.second_canal_check)
        self.stimulation_type_window2.addWidget(self.stim_type_cell2)
        self.canal_window.addLayout(self.stimulation_type_window2)

        self.different_signals_window2 = QStackedLayout()
        self.canal_window.addLayout(self.different_signals_window2)

        self.third_canal_check = QCheckBox()
        self.third_canal_check.stateChanged.connect(self.canals_to_tree)
        self.third_canal_check.setText("Canal 3")
        # self.canal_window.addWidget(self.third_canal_check)

        self.stim_type_cell3 = QComboBox()
        self.stim_type_cell3.addItem("square")
        self.stim_type_cell3.addItem("random-square")
        self.stim_type_cell3.addItem("Third")
        self.stim_type_cell3.currentIndexChanged.connect(self.type_to_tree)
        self.stimulation_type_window3 = QHBoxLayout()
        self.stimulation_type_window3.addWidget(self.third_canal_check)
        # self.stimulation_type_window3.addWidget(self.stim_type_cell3)
        self.canal_window.addLayout(self.stimulation_type_window3)

        self.different_signals_window3 = QStackedLayout()
        self.canal_window.addLayout(self.different_signals_window3)

        self.stimulation_name_label = QLabel("Stimulation Name")
        self.stimulation_name_cell = QLineEdit()
        self.stimulation_name_cell.textEdited.connect(self.name_to_tree)
        self.stimulation_name_window = QHBoxLayout()
        self.stimulation_name_window.addWidget(self.stimulation_name_label)
        self.stimulation_name_window.addWidget(self.stimulation_name_cell)
        self.stimulation_edit_layout.addLayout(self.stimulation_name_window)

        self.duration_window = QHBoxLayout()
        self.first_signal_type_duration_label = QLabel("Duration (s)")
        self.duration_window.addWidget(self.first_signal_type_duration_label)
        self.duration_cell = QLineEdit()
        self.duration_window.addWidget(self.duration_cell)
        self.duration_cell.setValidator(self.onlyFloat)
        self.duration_cell.textEdited.connect(self.signal_to_tree)
        self.stimulation_edit_layout.addLayout(self.duration_window)

        self.baseline_checkbox = QCheckBox("Baseline")
        self.baseline_checkbox.stateChanged.connect(self.canals_to_tree)
        if self.acquisition_mode:
            self.stimulation_edit_layout.addWidget(self.baseline_checkbox)
        self.stimulation_edit_layout.addLayout(self.canal_window)

        self.first_signal_type_window = QVBoxLayout()
        self.first_signal_type_window.setAlignment(Qt.AlignLeft)
        self.first_signal_type_window.setAlignment(Qt.AlignTop)
        self.first_signal_type_window.setContentsMargins(0, 0, 0, 0)
        self.first_signal_type_container = QWidget()
        self.first_signal_type_container.setLayout(self.first_signal_type_window)

        self.first_signal_type_window2 = QVBoxLayout()
        self.first_signal_type_window2.setAlignment(Qt.AlignLeft)
        self.first_signal_type_window2.setAlignment(Qt.AlignTop)
        self.first_signal_type_window2.setContentsMargins(0, 0, 0, 0)
        self.first_signal_type_container2 = QWidget()
        self.first_signal_type_container2.setLayout(self.first_signal_type_window2)

        self.first_signal_type_window3 = QVBoxLayout()
        self.first_signal_type_window3.setAlignment(Qt.AlignLeft)
        self.first_signal_type_window3.setAlignment(Qt.AlignTop)
        self.first_signal_type_window3.setContentsMargins(0, 0, 0, 0)
        self.first_signal_type_container3 = QWidget()
        self.first_signal_type_container3.setLayout(self.first_signal_type_window3)

        self.pulses_window = QHBoxLayout()
        self.pulses_label = QLabel("Pulses")
        self.pulses_window.addWidget(self.pulses_label)
        self.pulses_cell = QLineEdit()
        self.pulses_cell.setValidator(QIntValidator())
        self.pulses_cell.textEdited.connect(self.signal_to_tree)
        self.pulses_window.addWidget(self.pulses_cell)

        self.pulses_window2 = QHBoxLayout()
        self.pulses_label2 = QLabel("Pulses")
        self.pulses_window2.addWidget(self.pulses_label2)
        self.pulses_cell2 = QLineEdit()
        self.pulses_cell2.setValidator(QIntValidator())
        self.pulses_cell2.textEdited.connect(self.signal_to_tree)
        self.pulses_window2.addWidget(self.pulses_cell2)

        self.pulses_window3 = QHBoxLayout()
        self.pulses_label3 = QLabel("Pulses")
        self.pulses_window3.addWidget(self.pulses_label3)
        self.pulses_cell3 = QLineEdit()
        self.pulses_cell3.setValidator(QIntValidator())
        self.pulses_cell3.textEdited.connect(self.signal_to_tree)
        self.pulses_window3.addWidget(self.pulses_cell3)

        self.jitter_window = QHBoxLayout()
        self.jitter_label = QLabel("Jitter (s)")
        self.jitter_window.addWidget(self.jitter_label)
        self.jitter_cell = QLineEdit()
        self.jitter_cell.setValidator(self.onlyFloat)
        self.jitter_cell.setText("0")
        self.jitter_cell.textEdited.connect(self.signal_to_tree)
        self.jitter_window.addWidget(self.jitter_cell)

        self.jitter_window2 = QHBoxLayout()
        self.jitter_window2 = QHBoxLayout()
        self.jitter_label2 = QLabel("Jitter (s)")
        self.jitter_window2.addWidget(self.jitter_label2)
        self.jitter_cell2 = QLineEdit()
        self.jitter_cell2.setValidator(self.onlyFloat)
        self.jitter_cell2.setText("0")
        self.jitter_cell2.textEdited.connect(self.signal_to_tree)
        self.jitter_window2.addWidget(self.jitter_cell2)

        self.jitter_window3 = QHBoxLayout()
        self.jitter_window3 = QHBoxLayout()
        self.jitter_label3 = QLabel("Jitter (s)")
        self.jitter_window3.addWidget(self.jitter_label3)
        self.jitter_cell3 = QLineEdit()
        self.jitter_cell3.setValidator(self.onlyFloat)
        self.jitter_cell3.setText("0")
        self.jitter_cell3.textEdited.connect(self.signal_to_tree)
        self.jitter_window3.addWidget(self.jitter_cell3)

        self.width_window = QHBoxLayout()
        self.width_label = QLabel("Width (s)")
        self.width_window.addWidget(self.width_label)
        self.width_cell = QLineEdit()
        self.width_cell.setValidator(self.onlyFloat)
        self.width_cell.setText("0")
        self.width_cell.textEdited.connect(self.signal_to_tree)
        self.width_window.addWidget(self.width_cell)

        self.width_window2 = QHBoxLayout()
        self.width_label2 = QLabel("Width (s)")
        self.width_window2.addWidget(self.width_label2)
        self.width_cell2 = QLineEdit()
        self.width_cell2.setValidator(self.onlyFloat)
        self.width_cell2.setText("0")
        self.width_cell2.textEdited.connect(self.signal_to_tree)
        self.width_window2.addWidget(self.width_cell2)

        self.width_window3 = QHBoxLayout()
        self.width_label3 = QLabel("Width (s)")
        self.width_window3.addWidget(self.width_label3)
        self.width_cell3 = QLineEdit()
        self.width_cell3.setValidator(self.onlyFloat)
        self.width_cell3.setText("0")
        self.width_cell3.textEdited.connect(self.signal_to_tree)
        self.width_window3.addWidget(self.width_cell3)

        self.first_signal_type_window.addLayout(self.pulses_window)
        self.first_signal_type_window.addLayout(self.width_window)
        self.first_signal_type_window.addLayout(self.jitter_window)

        self.first_signal_type_window2.addLayout(self.pulses_window2)
        self.first_signal_type_window2.addLayout(self.width_window2)
        self.first_signal_type_window2.addLayout(self.jitter_window2)

        self.first_signal_type_window3.addLayout(self.pulses_window3)
        self.first_signal_type_window3.addLayout(self.width_window3)
        self.first_signal_type_window3.addLayout(self.jitter_window3)
        # -------------------

        self.second_signal_type_window = QVBoxLayout()
        self.second_signal_type_container = QWidget()
        self.second_signal_type_window.setAlignment(Qt.AlignLeft)
        self.second_signal_type_window.setAlignment(Qt.AlignTop)
        self.second_signal_type_window.setContentsMargins(0, 0, 0, 0)
        self.second_signal_type_container.setLayout(self.second_signal_type_window)
        # self.stimulation_edit_layout.addLayout(self.different_signals_window)

        self.second_signal_type_window2 = QVBoxLayout()
        self.second_signal_type_container2 = QWidget()
        self.second_signal_type_window2.setAlignment(Qt.AlignLeft)
        self.second_signal_type_window2.setAlignment(Qt.AlignTop)
        self.second_signal_type_window2.setContentsMargins(0, 0, 0, 0)
        self.second_signal_type_container2.setLayout(self.second_signal_type_window2)

        self.second_signal_type_window3 = QVBoxLayout()
        self.second_signal_type_container3 = QWidget()
        self.second_signal_type_window3.setAlignment(Qt.AlignLeft)
        self.second_signal_type_window3.setAlignment(Qt.AlignTop)
        self.second_signal_type_window3.setContentsMargins(0, 0, 0, 0)
        self.second_signal_type_container3.setLayout(self.second_signal_type_window3)

        self.heigth_window = QHBoxLayout()
        self.heigth_label = QLabel("Heigth (V)")
        self.heigth_window.addWidget(self.heigth_label)
        self.heigth_cell = QLineEdit()
        self.heigth_cell.setValidator(self.onlyFloat)
        self.heigth_cell.textEdited.connect(self.signal_to_tree)
        self.heigth_window.addWidget(self.heigth_cell)

        self.heigth_window2 = QHBoxLayout()
        self.heigth_label2 = QLabel("Heigth (V)")
        self.heigth_window2.addWidget(self.heigth_label2)
        self.heigth_cell2 = QLineEdit()
        self.heigth_cell2.setValidator(self.onlyFloat)
        self.heigth_cell2.textEdited.connect(self.signal_to_tree)
        self.heigth_window2.addWidget(self.heigth_cell2)

        self.heigth_window3 = QHBoxLayout()
        self.heigth_label3 = QLabel("Heigth (V)")
        self.heigth_window3.addWidget(self.heigth_label3)
        self.heigth_cell3 = QLineEdit()
        self.heigth_cell3.setValidator(self.onlyFloat)
        self.heigth_cell3.textEdited.connect(self.signal_to_tree)
        self.heigth_window3.addWidget(self.heigth_cell3)

        self.frequency_window = QHBoxLayout()
        self.frequency_label = QLabel("Frequency (Hz)")
        self.frequency_window.addWidget(self.frequency_label)
        self.frequency_cell = QLineEdit()
        self.frequency_cell.setValidator(self.onlyFloat)
        self.frequency_cell.textEdited.connect(self.signal_to_tree)
        self.frequency_window.addWidget(self.frequency_cell)

        self.frequency_window2 = QHBoxLayout()
        self.frequency_label2 = QLabel("Frequency (Hz)")
        self.frequency_window2.addWidget(self.frequency_label2)
        self.frequency_cell2 = QLineEdit()
        self.frequency_cell2.setValidator(self.onlyFloat)
        self.frequency_cell2.textEdited.connect(self.signal_to_tree)
        self.frequency_window2.addWidget(self.frequency_cell2)

        self.frequency_window3 = QHBoxLayout()
        self.frequency_label3 = QLabel("Frequency (Hz)")
        self.frequency_window3.addWidget(self.frequency_label3)
        self.frequency_cell3 = QLineEdit()
        self.frequency_cell3.setValidator(self.onlyFloat)
        self.frequency_cell3.textEdited.connect(self.signal_to_tree)
        self.frequency_window3.addWidget(self.frequency_cell3)

        self.duty_window = QHBoxLayout()
        self.duty_label = QLabel("Duty (%)")
        self.duty_window.addWidget(self.duty_label)
        self.duty_cell = QLineEdit()
        self.duty_cell.setValidator(self.onlyFloat)
        self.duty_cell.textEdited.connect(self.signal_to_tree)
        self.duty_window.addWidget(self.duty_cell)

        self.duty_window2 = QHBoxLayout()
        self.duty_label2 = QLabel("Duty (%)")
        self.duty_window2.addWidget(self.duty_label2)
        self.duty_cell2 = QLineEdit()
        self.duty_cell2.setValidator(self.onlyFloat)
        self.duty_cell2.textEdited.connect(self.signal_to_tree)
        self.duty_window2.addWidget(self.duty_cell2)

        self.duty_window3 = QHBoxLayout()
        self.duty_label3 = QLabel("Duty (%)")
        self.duty_window3.addWidget(self.duty_label3)
        self.duty_cell3 = QLineEdit()
        self.duty_cell3.setValidator(self.onlyFloat)
        self.duty_cell3.textEdited.connect(self.signal_to_tree)
        self.duty_window3.addWidget(self.duty_cell3)

        self.second_signal_type_window.addLayout(self.heigth_window)
        self.second_signal_type_window.addLayout(self.frequency_window)
        self.second_signal_type_window.addLayout(self.duty_window)

        self.second_signal_type_window2.addLayout(self.heigth_window2)
        self.second_signal_type_window2.addLayout(self.frequency_window2)
        self.second_signal_type_window2.addLayout(self.duty_window2)

        # self.second_signal_type_window3.addLayout(self.heigth_window3)
        self.second_signal_type_window3.addLayout(self.frequency_window3)
        self.second_signal_type_window3.addLayout(self.duty_window3)

        # -------------------

        self.third_signal_type_window = QVBoxLayout()
        self.third_signal_type_container = QWidget()
        self.third_signal_type_container.setLayout(self.third_signal_type_window)

        self.third_signal_type_window2 = QVBoxLayout()
        self.third_signal_type_container2 = QWidget()
        self.third_signal_type_container2.setLayout(self.third_signal_type_window2)

        self.third_signal_type_window3 = QVBoxLayout()
        self.third_signal_type_container3 = QWidget()
        self.third_signal_type_container3.setLayout(self.third_signal_type_window3)

        self.third_signal_type_name = QLabel("signal3")
        self.third_signal_type_window.addWidget(self.third_signal_type_name)

        self.third_signal_type_name2 = QLabel("signal3")
        self.third_signal_type_window2.addWidget(self.third_signal_type_name2)

        self.third_signal_type_name3 = QLabel("signal3")
        self.third_signal_type_window3.addWidget(self.third_signal_type_name3)

        self.different_signals_window.addWidget(self.second_signal_type_container)
        self.different_signals_window.addWidget(self.first_signal_type_container)
        self.different_signals_window.addWidget(self.third_signal_type_container)

        self.different_signals_window2.addWidget(self.second_signal_type_container2)
        self.different_signals_window2.addWidget(self.first_signal_type_container2)
        self.different_signals_window2.addWidget(self.third_signal_type_container2)

        self.different_signals_window3.addWidget(self.second_signal_type_container3)
        self.different_signals_window3.addWidget(self.first_signal_type_container3)
        self.different_signals_window3.addWidget(self.third_signal_type_container3)

        self.stimulation_edit_container = QWidget()
        self.stimulation_edit_container.setLayout(self.stimulation_edit_layout)
        self.block_edit_layout = QVBoxLayout()
        self.block_edit_layout.setContentsMargins(0, 0, 0, 0)
        self.block_edit_layout.setAlignment(Qt.AlignLeft)
        self.block_edit_layout.setAlignment(Qt.AlignTop)

        self.block_name_label = QLabel("Block Name")
        self.block_name_cell = QLineEdit()
        self.block_name_cell.textEdited.connect(self.name_to_tree)
        self.block_name_window = QHBoxLayout()
        self.block_name_window.addWidget(self.block_name_label)
        self.block_name_window.addWidget(self.block_name_cell)
        self.block_edit_layout.addLayout(self.block_name_window)

        self.block_iterations_window = QHBoxLayout()
        self.block_iterations_label = QLabel("Iterations")
        self.block_iterations_cell = QLineEdit()
        self.block_iterations_cell.setValidator(QIntValidator())
        self.block_iterations_cell.textEdited.connect(self.block_to_tree)
        self.block_iterations_window.addWidget(self.block_iterations_label)
        self.block_iterations_window.addWidget(self.block_iterations_cell)
        self.block_edit_layout.addLayout(self.block_iterations_window)

        self.block_delay_window = QHBoxLayout()
        self.block_delay_label = QLabel("Delay")
        self.block_delay_cell = QLineEdit()
        self.block_delay_cell.setValidator(self.onlyFloat)
        self.block_delay_cell.textEdited.connect(self.block_to_tree)
        self.block_delay_window = QHBoxLayout()
        self.block_delay_window.addWidget(self.block_delay_label)
        self.block_delay_window.addWidget(self.block_delay_cell)
        self.block_edit_layout.addLayout(self.block_delay_window)

        self.block_jitter_window = QHBoxLayout()
        self.block_jitter_label = QLabel("Jitter")
        self.block_jitter_cell = QLineEdit()
        self.block_jitter_cell.setValidator(self.onlyFloat)
        self.block_jitter_cell.textEdited.connect(self.block_to_tree)
        self.block_jitter_window = QHBoxLayout()
        self.block_jitter_window.addWidget(self.block_jitter_label)
        self.block_jitter_window.addWidget(self.block_jitter_cell)
        self.block_edit_layout.addLayout(self.block_jitter_window)

        self.block_edit_container = QWidget()
        self.block_edit_container.setLayout(self.block_edit_layout)
        self.signal_adjust_superposed.addWidget(self.stimulation_edit_container)
        self.signal_adjust_superposed.addWidget(self.block_edit_container)
        self.signal_adjust_superposed.addWidget(QLabel())
        self.signal_adjust_superposed.setCurrentIndex(2)
        self.grid_layout.addLayout(self.signal_adjust_superposed, 3, 1)

        self.signal_preview_label = QLabel("Signal Preview")
        self.signal_preview_label.setFont(QFont("IBM Plex Sans", 17))
        if self.acquisition_mode:
            self.grid_layout.addWidget(self.signal_preview_label, 2, 2)
        else:
            self.grid_layout.addWidget(self.signal_preview_label, 0, 2)

        self.buttons_main_window = QHBoxLayout()
        self.stop_button = QPushButton("Stop")
        self.stop_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "player-stop.png"))
        )
        self.stop_button.clicked.connect(self.stop_while_running)
        self.stop_button.setEnabled(False)
        self.buttons_main_window.addWidget(self.stop_button)
        self.run_button = QPushButton("Run")
        self.run_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "player-play.png"))
        )
        self.run_button.clicked.connect(self.run)
        self.run_button.setEnabled(False)
        self.buttons_main_window.addWidget(self.run_button)
        self.plot_window = PlotWindow(subplots=True)
        if self.acquisition_mode:
            self.grid_layout.addWidget(self.plot_window, 3, 2)
        else:
            self.grid_layout.addWidget(self.plot_window, 1, 2, 3, 1)
        self.grid_layout.addLayout(self.buttons_main_window, 4, 2)
        self.open_daq_generation_thread()
        self.initialize_buttons()
        self.show()

    def deactivate_channels(self):
        """Deactivate canal checkboxes if the baseline checkbox is checked"""
        if self.baseline_checkbox.isChecked():
            self.deactivate_buttons(
                [
                    self.first_canal_check,
                    self.second_canal_check,
                ]
            )
        else:
            self.activate_buttons(
                [
                    self.first_canal_check,
                    self.second_canal_check,
                ]
            )

    def adjust_exposure(self):
        """Match the exposure of the image preview to the slider value"""
        self.max_exposure = self.exposure_slider.value()
        self.slider_values[self.preview_light_combo.currentText()][
            self.activation_map_combo.currentText()
        ] = self.max_exposure

    def set_trigger(self):
        """Set the trigger for the DAQ"""
        if not self.acquisition_mode:
            self.run_button.setText("Run at Trigger")
            self.daq.set_trigger(self.ports["trigger"])
        else:
            self.run_button.setText("Run")
            self.daq.remove_trigger()

    def import_config(self):
        """Import a configuration file"""
        file = QFileDialog.getOpenFileName()[0]
        try:
            dictionary = get_dictionary(file)
            self.framerate_cell.setText(str(dictionary["Framerate"]))
            self.exposure_cell.setText(str(dictionary["Exposition"]))
            self.set_lights(dictionary["Lights"])
            self.tree.create_tree_item(dictionary["Blocks"])
            self.enable_run(self.tree.check_global_validity())
            self.tree.graph(self.tree.invisibleRootItem())
            self.draw()
        except Exception as err:
            print(err)

    def set_lights(self, lights):
        """Set the lights"""
        for light in lights:
            if light == "infrared":
                self.ir_checkbox.setChecked(True)
            elif light == "red":
                self.red_checkbox.setChecked(True)
            elif light == "green":
                self.green_checkbox.setChecked(True)
            elif light == "blue":
                self.fluorescence_checkbox.setChecked(True)

    def run(self):
        """Run the experiment"""
        if self.check_override():
            self.deactivate_buttons(buttons=self.enabled_buttons)
            self.master_block = self.tree.create_blocks()
            self.tree.baseline_values = []
            self.tree.graph(item=self.tree.invisibleRootItem())
            self.root_time, self.root_signal = (
                self.tree.x_values,
                [
                    self.tree.stim1_values,
                    self.tree.stim2_values,
                    self.tree.stim3_values,
                ],
            )
            self.draw(root=True)
            if self.acquisition_mode:
                self.actualize_daq()
                self.open_live_saving_thread()
                self.open_live_preview_thread()
                self.open_baseline_check_thread()
            else:
                self.daq.stop_signal = False
            self.open_signal_preview_thread()
            self.open_start_experiment_thread()

    def check_override(self):
        """Check if experiment with the same name already exists"""
        if os.path.isfile(
            os.path.join(
                self.directory_cell.text(),
                self.experiment_name_cell.text(),
                f"{self.experiment_name_cell.text()}-light_signal.npy",
            )
        ):
            button = QMessageBox.question(
                self,
                "Files already exist",
                "Files already exist. \n Do you want to override the existing files?",
            )
            if button == QMessageBox.Yes:
                return True
            else:
                return False
        else:
            return True

    def open_baseline_check_thread(self):
        """Open the thread for the baseline check"""
        self.baseline_check_thread = Thread(target=self.check_baseline)
        self.baseline_check_thread.start()

    def check_baseline(self):
        """Monitor the incoming frames and check if the baseline is reached"""
        if len(self.daq.lights) > 0:
            self.camera.baseline_data = []
            self.camera.adding_frames = False
            self.camera.completed_baseline = False
            while self.daq.camera_signal is None:
                pass
            frames_acquired = frames_acquired_from_camera_signal(self.daq.camera_signal)
            baseline_indices = get_baseline_frame_indices(
                self.tree.baseline_values, frames_acquired
            )
            for baseline_pair in baseline_indices:
                while not self.daq.stop_signal:
                    try:
                        if (
                            not self.camera.adding_frames
                            and self.camera.frames_read >= baseline_pair[0]
                        ):
                            self.camera.adding_frames = True
                        elif (
                            self.camera.adding_frames
                            and self.camera.frames_read >= baseline_pair[1]
                        ):
                            self.camera.baseline_read_list = []
                            self.camera.average_baseline = average_baseline(
                                self.camera.baseline_data,
                                len(self.daq.lights),
                                self.camera.frames_read_list[0] % len(self.daq.lights),
                            )
                            self.camera.adding_frames = False
                            self.camera.baseline_frames = []
                            self.camera.baseline_completed = True
                            self.camera.frames_read_list = []
                            break
                    except Exception as err:
                        pass
                    time.sleep(0.01)

    def open_start_experiment_thread(self):
        """Open the thread for the start of the experiment"""
        self.start_experiment_thread = Thread(target=self.run_stimulation)
        self.start_experiment_thread.start()

    def save_config(self):
        """Save the current configuration to a JSON file"""
        folder = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        if folder != "":
            self.master_block = self.tree.create_blocks()
            self.experiment = Experiment(
                self.master_block,
                int(self.framerate_cell.text()),
                int(self.exposure_cell.text()),
                self.mouse_id_cell.text(),
                folder,
                self.daq,
                name=self.experiment_name_cell.text(),
                config=self.config,
            )
            self.experiment.save_config(
                [int(1024 / self.config["Binning"]), int(1024 / self.config["Binning"])]
            )

    def run_stimulation(self):
        """Run the stimulation in parallel with the lights"""
        self.experiment = Experiment(
            self.master_block,
            int(self.framerate_cell.text()),
            int(self.exposure_cell.text()),
            self.mouse_id_cell.text(),
            self.directory_cell.text(),
            self.daq,
            name=self.experiment_name_cell.text(),
            config=self.config,
        )
        self.save_files_after_stop = True
        self.daq.launch(self.experiment.name, self.root_time, self.root_signal)
        # if (
        #    not self.daq.stop_signal
        #    and self.save_files_after_stop
        #    and self.directory_save_files_checkbox.isChecked()
        # ):
        if (
            self.save_files_after_stop
            and self.directory_save_files_checkbox.isChecked()
        ):
            try:
                print("this is the extent")
                print(self.roi_extent)
                self.experiment.save(self.roi_extent)
            except Exception as err:
                print("err after saving first")
                print(err)
                print("err before entering")
                self.experiment.save()
        self.stop()

    def open_live_saving_thread(self):
        """Open the thread for the live saving"""
        self.live_save_thread = Thread(target=self.live_save)
        self.live_save_thread.start()

    def live_save(self):
        """Save NPY chunked files when the number of frames is over 1200"""
        self.camera.file_index = 0
        self.camera.is_saving = False
        if self.directory_save_files_checkbox.isChecked():
            try:
                os.mkdir(
                    os.path.join(
                        self.directory_cell.text(), self.experiment_name_cell.text()
                    )
                )
                os.mkdir(
                    os.path.join(
                        self.directory_cell.text(),
                        self.experiment_name_cell.text(),
                        "data",
                    )
                )
            except Exception as err:
                pass
            while self.camera.video_running is False and not self.camera.stop_signal:
                time.sleep(0.01)
                pass
            while self.camera.video_running is True:
                if len(self.camera.frames) > 1200:
                    self.memory = self.camera.frames[:1200]
                    self.camera.frames = self.camera.frames[1200:]
                    if self.directory_save_files_checkbox.isChecked():
                        try:
                            self.memory = shrink_array(self.memory, self.roi_extent)
                        except Exception:
                            pass
                        self.camera.is_saving = True
                        np.save(
                            os.path.join(
                                self.directory_cell.text(),
                                self.experiment_name_cell.text(),
                                "data",
                                f"{self.camera.file_index}.npy",
                            ),
                            self.memory,
                        )
                        self.memory = None
                        self.camera.file_index += 1
                        self.camera.is_saving = False
                time.sleep(0.01)

    def open_live_preview_thread(self):
        """Open the thread for the live preview"""
        self.live_preview_thread = Thread(target=self.start_live)
        self.live_preview_thread.start()

    def start_live(self):
        """Start the live preview"""
        plt.ion()
        self.memory = []
        self.camera.baseline_completed = False
        if len(self.daq.lights) > 0:
            try:
                while self.camera.video_running is False:
                    time.sleep(0.01)
                    pass
                while self.camera.video_running is True:
                    try:
                        if (
                            not self.camera.baseline_completed
                            or self.activation_map_combo.currentIndex() == 0
                        ):
                            self.plot_image.set(
                                array=self.camera.frames[
                                    self.live_preview_light_index :: len(
                                        self.daq.lights
                                    )
                                ][-1],
                                clim=(0, self.max_exposure),
                                cmap="binary_r",
                            )
                        elif self.activation_map_combo.currentIndex() == 1:
                            start_index = (
                                self.camera.baseline_read_list[0]
                                + self.live_preview_light_index
                            ) % len(self.daq.lights)
                            activation_map = (
                                self.camera.baseline_frames[
                                    start_index :: len(self.daq.lights)
                                ][-1]
                                - self.camera.average_baseline[
                                    self.live_preview_light_index
                                ]
                            ) / self.camera.average_baseline[
                                self.live_preview_light_index
                            ]
                            self.plot_image.set(
                                array=activation_map,
                                clim=(
                                    -self.max_exposure / 200,
                                    self.max_exposure / 200,
                                ),
                                cmap="seismic",
                            )
                        else:
                            start_index = (
                                self.camera.baseline_read_list[0]
                                + self.live_preview_light_index
                            ) % len(self.daq.lights)
                            activation_map = np.log(
                                (
                                    (
                                        self.camera.baseline_frames[
                                            start_index :: len(self.daq.lights)
                                        ][-1]
                                        - self.camera.average_baseline[
                                            self.live_preview_light_index
                                        ]
                                    )
                                    / self.camera.average_baseline[
                                        self.live_preview_light_index
                                    ]
                                )
                            )
                            self.plot_image.set(
                                array=activation_map,
                                clim=(
                                    -self.max_exposure / 2000,
                                    self.max_exposure / 2000,
                                ),
                                cmap="seismic",
                            )

                    except Exception as err:
                        print(err)
                        pass
                    time.sleep(0.04)
            except Exception as err:
                pass

    def stop_live(self):
        """Stop the live preview"""
        self.camera.video_running = False

    def open_signal_preview_thread(self):
        """Open the thread for the signal preview"""
        self.signal_preview_thread = Thread(target=self.actualize_progression)
        self.signal_preview_thread.start()

    def actualize_progression(self):
        """Actualize the position of the progress bar"""
        plt.ion()
        while self.daq.stop_signal is False:
            try:
                if self.acquisition_mode:
                    position = self.camera.frames_read / int(self.framerate_cell.text())
                else:
                    position = time.time() - self.daq.start_time
                self.plot_window.vertical_lines[0].set_xdata(position)
                self.plot_window.vertical_lines[1].set_xdata(position)
                self.plot_window.vertical_lines[2].set_xdata(position)
                time.sleep(0.5)
            except Exception as err:
                time.sleep(0.5)
                pass

    def change_preview_light_channel(self):
        """Change the light channel for the live preview"""
        self.live_preview_light_index = self.preview_light_combo.currentIndex()
        self.adjust_slider()

    def adjust_slider(self):
        """Adjust the saturation slider using corresponding value in dictionary"""
        try:
            value = self.slider_values[self.preview_light_combo.currentText()][
                self.activation_map_combo.currentText()
            ]
            self.exposure_slider.setValue(value)
        except Exception:
            pass

    def open_daq_generation_thread(self):
        """Open the thread for the DAQ generation"""
        self.daq_generation_thread = Thread(target=self.generate_daq)
        self.daq_generation_thread.start()

    def generate_daq(self):
        """Generate the DAQ"""
        try:
            self.camera = Camera(self.ports["camera"], "name")
        except Exception:
            self.camera = None
        self.stimuli = [
            Instrument(self.ports["analog0"], "air-pump"),
            Instrument(self.ports["analog1"], "air-pump2"),
            Instrument(self.ports["co2"], "air-pump3"),
        ]
        self.daq = DAQ(
            "dev1",
            [],
            self.stimuli,
            self.camera,
            int(self.framerate_cell.text()),
            int(self.exposure_cell.text()) / 1000,
        )
        self.daq.close_all_lights(self.ports)
        self.daq_generated = True
        self.enable_run(self.tree.check_global_validity())

    def actualize_daq(self):
        """Actualize the DAQ with the current settings"""
        try:
            self.daq.lights = []
            if self.ir_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["infrared"], "ir"))
            if self.red_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["red"], "red"))
            if self.green_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["green"], "green"))
            if self.fluorescence_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["blue"], "blue"))
            self.daq.framerate = int(self.framerate_cell.text())
            self.daq.exposure = int(self.exposure_cell.text()) / 1000
            self.camera.frames = []
            self.daq.stop_signal = False
        except Exception:
            pass

    def stop(self):
        """Stop the experiment and reactivate the interface"""
        self.stop_live()
        self.activate_buttons(buttons=self.enabled_buttons)
        self.tree.setCurrentItem(self.tree.topLevelItem(0))
        try:
            self.daq.stop_signal = True
        except Exception:
            pass

    def stop_while_running(self):
        """Stop the experiment while it is running"""
        if self.directory_save_files_checkbox.isChecked():
            self.stop_stimulation_dialog()
        self.stop()

    def stop_stimulation_dialog(self):
        """Ask if user wants to keep the files after experiment is stopped"""
        button = QMessageBox.question(
            self, "Save Files", "Do you want to save the current files?"
        )
        if button == QMessageBox.Yes:
            self.save_files_after_stop = True
        else:
            self.save_files_after_stop = False

    def show_buttons(self, buttons):
        """Show the buttons in a list"""
        for button in buttons:
            button.setVisible(True)

    def hide_buttons(self, buttons):
        """Hide the buttons in a list"""
        for button in buttons:
            button.setVisible(False)

    def activate_buttons(self, buttons):
        """Activate the buttons in a list"""
        for button in buttons:
            button.setEnabled(True)
        if buttons == self.enabled_buttons:
            if self.directory_save_files_checkbox.isChecked():
                self.directory_choose_button.setEnabled(True)
            if self.roi_extent is None:
                self.reset_roi_button.setEnabled(False)
            else:
                self.set_roi_button.setEnabled(False)
            self.stop_button.setDisabled(True)

    def deactivate_buttons(self, buttons):
        """Deactivate the buttons in a list"""
        if buttons == self.enabled_buttons:
            self.stop_button.setEnabled(True)
            self.tree.clearSelection()
        for button in buttons:
            button.setDisabled(True)

    def choose_directory(self):
        """Choose the directory where to save the files"""
        folder = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        self.directory_cell.setText(folder)

    def enable_directory(self):
        """Enable the directory cell"""
        self.files_saved = self.directory_save_files_checkbox.isChecked()
        self.directory_choose_button.setEnabled(self.files_saved)
        self.directory_cell.setEnabled(self.files_saved)

    def actualize_window(self):
        """Actualize the 'Stimulation Edit' and 'Signal Preview' windows"""
        self.activate_buttons(
            [self.add_child_branch_button, self.add_brother_branch_button]
        )
        if self.tree.currentItem():
            self.tree_switch_window.setCurrentIndex(0)
        else:
            self.tree_switch_window.setCurrentIndex(1)
        try:
            if self.tree.currentItem().childCount() > 0:
                self.signal_adjust_superposed.setCurrentIndex(1)
            else:
                self.signal_adjust_superposed.setCurrentIndex(0)
        except AttributeError:
            self.signal_adjust_superposed.setCurrentIndex(2)
        self.tree_to_name()
        self.tree_to_block()
        self.tree_to_type()
        self.tree_to_signal()
        self.tree_to_canal()
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()

    def name_to_tree(self):
        """Transfer the name of the current item from the cell to the tree"""
        branch = self.tree.currentItem()
        branch.setForeground(0, QBrush(QColor(0, 0, 0)))
        if branch.childCount() > 0:
            branch.setText(0, self.block_name_cell.text())
        else:
            branch.setText(0, self.stimulation_name_cell.text())

    def tree_to_name(self):
        """Transfer the name of the current item from the tree to the cell"""
        try:
            if self.tree.currentItem().childCount() > 0:
                if self.tree.currentItem().text(0) != "No Name":
                    self.block_name_cell.setText(self.tree.currentItem().text(0))
                else:
                    self.block_name_cell.setText("")
            else:
                if self.tree.currentItem().text(0) != "No Name":
                    self.stimulation_name_cell.setText(self.tree.currentItem().text(0))
                else:
                    self.stimulation_name_cell.setText("")
        except AttributeError:
            pass

    def type_to_tree(self):
        """Transfer the type of the current item from the cell to the tree"""
        self.enable_run(self.tree.check_global_validity())
        self.different_signals_window.setCurrentIndex(
            self.stim_type_cell.currentIndex()
        )
        self.different_signals_window2.setCurrentIndex(
            self.stim_type_cell2.currentIndex()
        )
        self.different_signals_window3.setCurrentIndex(
            self.stim_type_cell3.currentIndex()
        )
        try:
            self.tree.currentItem().setText(4, str(self.stim_type_cell.currentText()))
        except Exception:
            pass
        try:
            self.tree.currentItem().setText(11, str(self.stim_type_cell2.currentText()))
        except Exception:
            pass
        try:
            self.tree.currentItem().setText(23, str(self.stim_type_cell3.currentText()))
        except Exception:
            pass
        try:
            self.tree.graph(self.tree.currentItem(), current=True)
            self.draw()
        except Exception:
            pass

    def tree_to_type(self):
        """Transfer the type of the current item from the tree to the cell"""
        dico = {"square": 0, "random-square": 1, "Third": 2}
        try:
            self.stim_type_cell.setCurrentIndex(dico[self.tree.currentItem().text(4)])
        except Exception:
            self.stim_type_cell.setCurrentIndex(0)

        try:
            self.stim_type_cell2.setCurrentIndex(dico[self.tree.currentItem().text(11)])
        except Exception:
            self.stim_type_cell2.setCurrentIndex(0)

        try:
            self.stim_type_cell3.setCurrentIndex(dico[self.tree.currentItem().text(23)])
        except Exception:
            self.stim_type_cell3.setCurrentIndex(0)

    def signal_to_tree(self):
        """Transfer the signal of the current item from the cell to the tree"""
        self.tree.currentItem().setText(6, self.duration_cell.text())
        self.tree.currentItem().setText(5, self.pulses_cell.text())
        self.tree.currentItem().setText(7, self.jitter_cell.text())
        self.tree.currentItem().setText(8, self.width_cell.text())
        self.tree.currentItem().setText(9, self.frequency_cell.text())
        self.tree.currentItem().setText(10, self.duty_cell.text())
        self.tree.currentItem().setText(21, self.heigth_cell.text())
        self.tree.currentItem().setText(12, self.pulses_cell2.text())
        self.tree.currentItem().setText(13, self.jitter_cell2.text())
        self.tree.currentItem().setText(14, self.width_cell2.text())
        self.tree.currentItem().setText(15, self.frequency_cell2.text())
        self.tree.currentItem().setText(16, self.duty_cell2.text())
        self.tree.currentItem().setText(22, self.heigth_cell2.text())
        self.tree.currentItem().setText(24, self.pulses_cell3.text())
        self.tree.currentItem().setText(25, self.jitter_cell3.text())
        self.tree.currentItem().setText(26, self.width_cell3.text())
        self.tree.currentItem().setText(27, self.frequency_cell3.text())
        self.tree.currentItem().setText(28, self.duty_cell3.text())
        self.enable_run(self.tree.check_global_validity())
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()

    def tree_to_signal(self):
        """Transfer the signal of the current item from the tree to the cell"""
        try:
            self.pulses_cell.setText(self.tree.currentItem().text(5))
            self.duration_cell.setText(self.tree.currentItem().text(6))
            self.jitter_cell.setText(self.tree.currentItem().text(7))
            self.width_cell.setText(self.tree.currentItem().text(8))
            self.frequency_cell.setText(self.tree.currentItem().text(9))
            self.heigth_cell.setText(self.tree.currentItem().text(21))
            self.duty_cell.setText(self.tree.currentItem().text(10))
            self.pulses_cell2.setText(self.tree.currentItem().text(12))
            self.jitter_cell2.setText(self.tree.currentItem().text(13))
            self.width_cell2.setText(self.tree.currentItem().text(14))
            self.frequency_cell2.setText(self.tree.currentItem().text(15))
            self.heigth_cell2.setText(self.tree.currentItem().text(22))
            self.duty_cell2.setText(self.tree.currentItem().text(16))
            self.pulses_cell3.setText(self.tree.currentItem().text(24))
            self.jitter_cell3.setText(self.tree.currentItem().text(25))
            self.width_cell3.setText(self.tree.currentItem().text(26))
            self.frequency_cell3.setText(self.tree.currentItem().text(27))
            self.duty_cell3.setText(self.tree.currentItem().text(28))
        except Exception as err:
            pass

    def tree_to_block(self):
        """Transfer the block attributes from the tree to the cells"""
        try:
            self.block_iterations_cell.setText(self.tree.currentItem().text(1))
            self.block_delay_cell.setText(self.tree.currentItem().text(2))
            self.block_jitter_cell.setText(self.tree.currentItem().text(3))
        except Exception:
            pass

    def block_to_tree(self):
        """Transfer the block attributes from the cells to the tree"""
        self.tree.currentItem().setText(1, self.block_iterations_cell.text())
        self.tree.currentItem().setText(2, self.block_delay_cell.text())
        self.tree.currentItem().setText(3, self.block_jitter_cell.text())
        self.enable_run(self.tree.check_global_validity())
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()

    def tree_to_canal(self):
        """Transfer the canals attributes from the tree to the cells"""
        self.canal_running = True
        try:
            self.baseline_checkbox.setChecked(
                self.boolean(self.tree.currentItem().text(17))
            )
            self.first_canal_check.setChecked(
                self.boolean(self.tree.currentItem().text(18))
            )
            self.second_canal_check.setChecked(
                self.boolean(self.tree.currentItem().text(19))
            )
            self.third_canal_check.setChecked(
                self.boolean(self.tree.currentItem().text(30))
            )
            if self.baseline_checkbox.isChecked():
                self.deactivate_buttons(self.canal1buttons + [self.first_canal_check])
                self.deactivate_buttons(self.canal2buttons + [self.second_canal_check])
                self.deactivate_buttons(self.canal3buttons + [self.third_canal_check])
            else:
                self.activate_buttons(
                    [
                        self.first_canal_check,
                        self.second_canal_check,
                        self.third_canal_check,
                    ]
                )
            if self.first_canal_check.isChecked():
                self.activate_buttons(self.canal1buttons)
            else:
                self.deactivate_buttons(self.canal1buttons)
            if self.second_canal_check.isChecked():
                self.activate_buttons(self.canal2buttons)
            else:
                self.deactivate_buttons(self.canal2buttons)
            if self.third_canal_check.isChecked():
                self.activate_buttons(self.canal3buttons)
            else:
                self.deactivate_buttons(self.canal3buttons)
        except Exception as err:
            pass
        self.canal_running = False

    def canals_to_tree(self):
        """Transfer the canals attributes from the cells to the tree"""
        self.baseline_checkbox.setEnabled(True)
        if not self.canal_running:
            if self.baseline_checkbox.isChecked():
                self.deactivate_buttons(self.canal1buttons + [self.first_canal_check])
                self.deactivate_buttons(self.canal2buttons + [self.second_canal_check])
                self.deactivate_buttons(self.canal3buttons + [self.third_canal_check])
            else:
                self.activate_buttons(self.canal1buttons + [self.first_canal_check])
                self.activate_buttons(self.canal2buttons + [self.second_canal_check])
                self.activate_buttons(self.canal3buttons + [self.third_canal_check])
            if self.first_canal_check.isChecked():
                self.baseline_checkbox.setEnabled(False)
                self.activate_buttons(self.canal1buttons)
            else:
                self.deactivate_buttons(self.canal1buttons)
            if self.second_canal_check.isChecked():
                self.baseline_checkbox.setEnabled(False)
                self.activate_buttons(self.canal2buttons)
            else:
                self.deactivate_buttons(self.canal2buttons)
            if self.third_canal_check.isChecked():
                self.baseline_checkbox.setEnabled(False)
                self.activate_buttons(self.canal3buttons)
            else:
                self.deactivate_buttons(self.canal3buttons)
            if (
                self.first_canal_check.isChecked()
                or self.second_canal_check.isChecked()
                or self.third_canal_check.isChecked()
            ):
                self.deactivate_buttons([self.baseline_checkbox])
            else:
                self.activate_buttons([self.baseline_checkbox])
            self.tree.currentItem().setText(17, str(self.baseline_checkbox.isChecked()))
            self.tree.currentItem().setText(18, str(self.first_canal_check.isChecked()))
            self.tree.currentItem().setText(
                19, str(self.second_canal_check.isChecked())
            )
            self.tree.currentItem().setText(30, str(self.third_canal_check.isChecked()))
            self.enable_run(self.tree.check_global_validity())
            self.tree.graph(self.tree.currentItem(), current=True)
            self.draw()

    def enable_run(self, boolean):
        """Enable the run button"""
        if not self.daq_generated:
            boolean = False
        self.save_config_button.setEnabled(boolean)
        self.run_button.setEnabled(boolean)

    def disable_run(self):
        """Disable the run button"""
        self.save_config_button.setDisabled(True)
        self.run_button.setDisabled(True)

    def count_lights(self):
        """Return the number of lights and a list of their names"""
        count = 0
        text = []
        for checkbox in [
            self.ir_checkbox,
            self.red_checkbox,
            self.green_checkbox,
            self.fluorescence_checkbox,
        ]:
            if checkbox.isChecked():
                count += 1
                text.append(checkbox.text())
        return (count, text)

    def actualize_lights(self):
        """Update the lights list in the combo box"""
        self.preview_light_combo.clear()
        if self.count_lights()[0] == 0:
            self.preview_light_combo.setEnabled(False)
        else:
            self.preview_light_combo.setEnabled(True)
        for i in range(4):
            if i < self.count_lights()[0]:
                self.preview_light_combo.addItem(self.count_lights()[1][i])

    def boolean(self, string):
        """Return a boolean from a string"""
        if string == "True":
            return True
        return False

    def draw(self, root=False):
        """Draw the sitmulation channels graph
        
        Args:
            root (bool, optional): If True, the graph includes a progress bar"""
        try:
            self.plot_window.clear()
            self.plot_window.plot(
                self.tree.x_values, self.tree.stim1_values, root, index=0
            )
            self.plot_window.plot(
                self.tree.x_values,
                self.tree.stim2_values,
                root,
                index=1,
            )
            self.plot_window.plot(
                self.tree.x_values,
                self.tree.stim3_values,
                root,
                index=2,
            )
            self.tree.x_values = []
            self.tree.stim1_values = []
            self.tree.stim2_values = []
            self.tree.stim3_values = []
            self.elapsed_time = 0
        except Exception as err:
            pass

    def set_roi(self):
        """Set the ROI"""
        self.deactivate_buttons(buttons=self.enabled_buttons)
        self.stop_button.setEnabled(False)
        self.save_roi_button.setEnabled(False)
        self.roi_buttons.setCurrentIndex(1)

        def onselect_function(eclick, erelease):
            """Save the ROI dimensions as attributes"""
            self.roi_extent = self.rect_selector.extents
            self.save_roi_button.setEnabled(True)

        self.rect_selector = RectangleSelector(
            self.plot_image.axes,
            onselect_function,
            drawtype="box",
            useblit=True,
            button=[1, 3],
            minspanx=5,
            minspany=5,
            spancoords="pixels",
            interactive=True,
        )

    def reset_roi(self):
        """Reset the ROI"""
        plt.figure(self.image_view.figure.number)
        plt.xlim(0, int(1024 / self.config["Binning"]))
        plt.ylim(0, int(1024 / self.config["Binning"]))
        self.roi_extent = None
        self.reset_roi_button.setEnabled(False)

    def cancel_roi(self):
        """Cancel the ROI selection"""
        self.activate_buttons(buttons=self.enabled_buttons)
        self.roi_buttons.setCurrentIndex(0)
        self.rect_selector.clear()
        self.rect_selector = None

    def save_roi(self):
        """Save the ROI"""
        self.activate_buttons(buttons=self.enabled_buttons)
        self.roi_buttons.setCurrentIndex(0)
        plt.figure(self.image_view.figure.number)
        plt.ion()
        print(self.roi_extent)
        plt.xlim(self.roi_extent[0], self.roi_extent[1])
        plt.ylim(self.roi_extent[2], self.roi_extent[3])
        self.rect_selector.clear()
        self.rect_selector = None
        self.reset_roi_button.setEnabled(True)

    def verify_exposure(self):
        """Verify if the exposure/framerate combination is valid"""
        try:
            boolean_check = (int(self.exposure_cell.text()) / 1000 + 0.0015) * int(
                self.framerate_cell.text()
            ) < 1 and int(self.framerate_cell.text()) <= 57
        except Exception:
            boolean_check = False
        self.exposure_warning_label.setHidden(boolean_check)

    def check_if_thread_is_alive(self):
        """Check what threads are alive"""
        try:
            if self.live_preview_thread.is_alive():
                print("Live preview thread is alive")
            else:
                print("Live preview thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.start_experiment_thread.is_alive():
                print("Start Experiment thread is alive")
            else:
                print("Start experiment thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.daq_generation_thread.is_alive():
                print("Daq Generation thread is alive")
            else:
                print("Daq generation thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.signal_preview_thread.is_alive():
                print("Signal Preview thread is alive")
            else:
                print("Signal Preview thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.live_save_thread.is_alive():
                print("Live Save thread is alive")
            else:
                print("Live Save thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.baseline_check_thread.is_alive():
                print("Baseline check thread is alive")
            else:
                print("Baseline check thread is dead")
        except Exception as err:
            print(err)

    def initialize_buttons(self):
        """Define list of buttons to activate/deactivate"""
        self.canal1buttons = [
            self.stim_type_cell,
            self.pulses_label,
            self.pulses_cell,
            self.width_label,
            self.width_cell,
            self.jitter_label,
            self.jitter_cell,
            self.frequency_label,
            self.frequency_cell,
            self.duty_label,
            self.duty_cell,
            self.heigth_cell,
            self.heigth_label,
        ]
        self.canal2buttons = [
            self.stim_type_cell2,
            self.pulses_label2,
            self.pulses_cell2,
            self.width_label2,
            self.width_cell2,
            self.jitter_label2,
            self.jitter_cell2,
            self.frequency_label2,
            self.frequency_cell2,
            self.duty_label2,
            self.duty_cell2,
            self.heigth_cell2,
            self.heigth_label2,
        ]
        self.canal3buttons = [
            self.stim_type_cell3,
            self.pulses_label3,
            self.pulses_cell3,
            self.width_label3,
            self.width_cell3,
            self.jitter_label3,
            self.jitter_cell3,
            self.frequency_label3,
            self.frequency_cell3,
            self.duty_label3,
            self.duty_cell3,
            self.heigth_cell3,
            self.heigth_label3,
        ]
        self.enabled_buttons = [
            self.run_button,
            self.experiment_name_cell,
            self.mouse_id_cell,
            self.directory_choose_button,
            self.set_roi_button,
            self.reset_roi_button,
            self.experiment_name,
            self.mouse_id_label,
            self.framerate_label,
            self.framerate_cell,
            self.exposure_cell,
            self.exposure_label,
            self.add_brother_branch_button,
            self.add_child_branch_button,
            self.delete_item_button,
            self.red_checkbox,
            self.ir_checkbox,
            self.green_checkbox,
            self.fluorescence_checkbox,
            self.stimulation_name_label,
            self.directory_save_files_checkbox,
            self.stimulation_name_cell,
            self.stim_type_cell,
            self.stim_type_cell2,
            self.first_canal_check,
            self.second_canal_check,
            self.first_signal_type_duration_label,
            self.duration_cell,
            self.pulses_label,
            self.pulses_cell,
            self.width_label,
            self.width_cell,
            self.jitter_label,
            self.jitter_cell,
            self.frequency_label,
            self.frequency_cell,
            self.heigth_label,
            self.heigth_cell,
            self.duty_label,
            self.duty_cell,
            self.pulses_label2,
            self.pulses_cell2,
            self.width_label2,
            self.width_cell2,
            self.jitter_label2,
            self.jitter_cell2,
            self.frequency_label2,
            self.frequency_cell2,
            self.heigth_label2,
            self.heigth_cell2,
            self.duty_label2,
            self.duty_cell2,
            self.third_canal_check,
            self.stim_type_cell3,
            self.pulses_label3,
            self.pulses_cell3,
            self.width_label3,
            self.width_cell3,
            self.jitter_label3,
            self.jitter_cell3,
            self.frequency_label3,
            self.frequency_cell3,
            self.duty_label3,
            self.duty_cell3,
            self.heigth_cell3,
            self.heigth_label3,
            self.block_iterations_label,
            self.block_iterations_cell,
            self.block_delay_label,
            self.block_delay_cell,
            self.block_jitter_label,
            self.block_jitter_cell,
            self.block_name_label,
            self.block_name_cell,
            self.activate_live_preview_button,
            self.deactivate_live_preview_button,
            self.tree,
        ]


if __name__ == "__main__":
    app = QApplication(sys.argv)
    font = QFont()
    font.setFamily("IBM Plex Sans")
    app.setFont(font)
    ex = App()
    sys.exit(app.exec_())

Classes

class App

QWidget(parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags())

Initialize the application

Expand source code
class App(QWidget):
    def __init__(self):
        """Initialize the application"""
        super().__init__()
        qInstallMessageHandler(self.handler)
        self.cwd = os.path.dirname(os.path.dirname(__file__))
        self.config = get_dictionary(os.path.join(self.cwd, "config.json"))
        self.ports = self.config["Ports"]
        self.elapsed_time = 0
        self.files_saved = False
        self.save_files_after_stop = False
        self.roi_extent = None
        self.max_exposure = 4096
        self.slider_values = {
            "Infrared": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
            "Red": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
            "Green": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
            "Blue": {"None": 4096, "Normal": 4096, "Logarithmic": 4096},
        }
        self.daq_generated = False
        self.onlyFloat = QDoubleValidator()
        self.onlyFloat.setLocale(QLocale(QLocale.English, QLocale.UnitedStates))
        self.onlyFloat.setNotation(QDoubleValidator.StandardNotation)
        self.onlyFramerate = QIntValidator(1, 57, self)
        self.onlyExposure = QIntValidator(1, 900, self)
        self.start_container = QWidget()
        self.start_layout = QVBoxLayout()
        self.start_container.setLayout(self.start_layout)
        self.start_title = QLabel("Welcome to WideBrain!")
        self.start_title.setFont(QFont("IBM Plex Sans", 20, QFont.Bold))
        self.start_title.setAlignment(Qt.AlignCenter)
        self.start_image = QLabel()
        self.start_image.setPixmap(
            QPixmap(os.path.join(self.cwd, "assets", "logo-small.png"))
        )
        self.start_image.setAlignment(Qt.AlignCenter)
        self.start_description = QLabel("Choose the type of experiment you want to run")
        self.start_description.setFont(QFont("IBM Plex Sans", 14, QFont.Light))
        self.start_description.setWordWrap(True)
        self.start_description.setAlignment(Qt.AlignCenter)

        self.trigger_mode_button = QPushButton("Start in Trigger Mode")
        self.trigger_mode_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "bolt.png"))
        )
        self.trigger_mode_button.setFont(QFont("IBM Plex Sans", 15, QFont.Light))
        self.trigger_mode_button.clicked.connect(self.start_in_trigger_mode)

        self.acquisition_mode_button = QPushButton("Start in Acquisition Mode")
        self.acquisition_mode_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "camera.png"))
        )
        self.acquisition_mode_button.setFont(QFont("IBM Plex Sans", 15, QFont.Light))
        self.acquisition_mode_button.clicked.connect(self.start_in_acquisition_mode)

        self.start_buttons = QHBoxLayout()
        self.start_buttons.addWidget(self.trigger_mode_button)
        self.start_buttons.addWidget(self.acquisition_mode_button)

        self.start_layout.addWidget(self.start_title)
        self.start_layout.addWidget(self.start_image)
        self.start_layout.addWidget(self.start_description)
        self.start_layout.addLayout(self.start_buttons)

        self.grid_layout = QGridLayout()
        self.grid_layout.addWidget(self.start_container, 0, 0)

        self.setLayout(self.grid_layout)
        self.show()

    def start_in_trigger_mode(self):
        """Initialize the interface in trigger mode"""
        self.start_container.setParent(None)
        self.acquisition_mode = False
        self.initUI()

    def start_in_acquisition_mode(self):
        """Initialize the interface in acquisition mode"""
        self.start_container.setParent(None)
        self.acquisition_mode = True
        self.initUI()

    def closeEvent(self, *args, **kwargs):
        """Stop all processes when closing the application"""
        self.video_running = False
        try:
            self.camera.stop_signal = True
            self.camera.video_running = False
            self.daq.stop_signal = True
            self.daq.camera.cam.stop_acquisition()
            print("Program Closed")
        except Exception as err:
            pass
        self.check_if_thread_is_alive()

    def handler(*args, **kwargs):
        """Ignore Qt messages"""
        pass

    def initUI(self):
        """Initialize the user interface"""
        self.title = "Widefield Imaging Aquisition"
        self.dimensions = (10, 10, 640, 480)
        self.setWindowTitle(self.title)
        self.setGeometry(*self.dimensions)

        # self.grid_layout = QGridLayout()
        # self.setLayout(self.grid_layout)
        self.grid_layout.setAlignment(Qt.AlignTop)

        self.experiment_settings_label = QLabel("Experiment Settings")
        self.experiment_settings_label.setFont(QFont("IBM Plex Sans", 17))
        self.grid_layout.addWidget(self.experiment_settings_label, 0, 0)

        self.experiment_settings_main_window = QVBoxLayout()
        self.experiment_name_window = QHBoxLayout()
        self.experiment_name = QLabel("Experiment Name")
        self.experiment_name_window.addWidget(self.experiment_name)
        self.experiment_name_cell = QLineEdit()
        self.experiment_name_window.addWidget(self.experiment_name_cell)
        self.experiment_settings_main_window.addLayout(self.experiment_name_window)

        self.mouse_id_window = QHBoxLayout()
        self.mouse_id_label = QLabel("Mouse ID")
        self.mouse_id_window.addWidget(self.mouse_id_label)
        self.mouse_id_cell = QLineEdit()
        self.mouse_id_window.addWidget(self.mouse_id_cell)
        self.experiment_settings_main_window.addLayout(self.mouse_id_window)

        self.framerate_exposure_window = QHBoxLayout()
        self.exposure_window = QHBoxLayout()
        self.exposure_label = QLabel("Exposure (ms)")
        self.exposure_window.addWidget(self.exposure_label)
        self.exposure_cell = QLineEdit("10")
        self.exposure_cell.setValidator(self.onlyExposure)
        self.exposure_cell.textChanged.connect(self.verify_exposure)
        self.exposure_window.addWidget(self.exposure_cell)
        self.framerate_exposure_window.addLayout(self.exposure_window)
        self.framerate_window = QHBoxLayout()
        self.framerate_label = QLabel("Framerate")
        self.framerate_window.addWidget(self.framerate_label)
        self.framerate_cell = QLineEdit("30")
        self.framerate_cell.setValidator(self.onlyFramerate)
        self.framerate_cell.textChanged.connect(self.verify_exposure)
        self.framerate_window.addWidget(self.framerate_cell)
        self.framerate_exposure_window.addLayout(self.framerate_window)

        if self.acquisition_mode:
            self.experiment_settings_main_window.addLayout(
                self.framerate_exposure_window
            )

        self.exposure_warning_label = QLabel("Invalid Exposure / Frame Rate")
        if self.acquisition_mode:
            self.experiment_settings_main_window.addWidget(self.exposure_warning_label)
        self.exposure_warning_label.setStyleSheet("color: red")
        self.exposure_warning_label.setHidden(True)

        self.directory_window = QHBoxLayout()
        self.directory_save_files_checkbox = QCheckBox()
        self.directory_save_files_checkbox.setText("Save")
        self.directory_save_files_checkbox.stateChanged.connect(self.enable_directory)
        self.directory_window.addWidget(self.directory_save_files_checkbox)
        self.directory_choose_button = QPushButton("Select Directory")
        self.directory_choose_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "folder-plus.png"))
        )
        # self.directory_choose_button.setIcon(QIcon(os.path.join("gui", "icons", "folder-plus.png")))
        self.directory_choose_button.setDisabled(True)
        self.directory_choose_button.clicked.connect(self.choose_directory)
        self.directory_window.addWidget(self.directory_choose_button)
        self.directory_cell = QLineEdit("")
        self.directory_cell.setReadOnly(True)
        self.directory_window.addWidget(self.directory_cell)
        self.experiment_settings_main_window.addLayout(self.directory_window)
        self.trigger_checkbox = QCheckBox("Wait for Trigger")
        self.trigger_activated = False
        self.trigger_checkbox.stateChanged.connect(self.set_trigger)
        # self.experiment_settings_main_window.addWidget(self.trigger_checkbox)

        self.save_config_button = QPushButton("Save Config")
        self.save_config_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "save.png"))
        )
        self.save_config_button.clicked.connect(self.save_config)
        self.save_config_button.setEnabled(False)
        self.experiment_settings_main_window.addWidget(self.save_config_button)

        self.experiment_settings_main_window.addStretch()

        if self.acquisition_mode:
            self.grid_layout.addLayout(self.experiment_settings_main_window, 1, 0)
        else:
            self.grid_layout.addLayout(self.experiment_settings_main_window, 1, 0, 1, 2)

        self.image_settings_label = QLabel("Image Settings")
        self.image_settings_label.setFont(QFont("IBM Plex Sans", 17))
        if self.acquisition_mode:
            self.grid_layout.addWidget(self.image_settings_label, 0, 1)

        self.image_settings_main_window = QVBoxLayout()
        self.image_settings_main_window.setAlignment(Qt.AlignLeft)
        self.image_settings_main_window.setAlignment(Qt.AlignTop)

        self.image_settings_second_window = QHBoxLayout()
        self.ir_checkbox = QCheckBox("Infrared")
        self.ir_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.ir_checkbox)
        self.red_checkbox = QCheckBox("Red")
        self.red_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.red_checkbox)
        self.green_checkbox = QCheckBox("Green")
        self.green_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.green_checkbox)
        self.fluorescence_checkbox = QCheckBox("Blue")
        self.fluorescence_checkbox.stateChanged.connect(self.actualize_lights)
        self.image_settings_second_window.addWidget(self.fluorescence_checkbox)

        self.light_channel_layout = QHBoxLayout()
        self.preview_light_label = QLabel("Light Channel Preview")
        self.light_channel_layout.addWidget(self.preview_light_label)
        self.preview_light_combo = QComboBox()
        self.preview_light_combo.setEnabled(False)
        self.preview_light_combo.currentIndexChanged.connect(
            self.change_preview_light_channel
        )
        self.light_channel_layout.addWidget(self.preview_light_combo)
        # self.activation_map_checkbox = QCheckBox("Show Activation Map")
        self.activation_map_window = QHBoxLayout()
        self.activation_map_label = QLabel("Activation Map")
        self.activation_map_window.addWidget(self.activation_map_label)
        self.activation_map_combo = QComboBox()
        self.activation_map_combo.addItem("None")
        self.activation_map_combo.addItem("Normal")
        self.activation_map_combo.addItem("Logarithmic")
        self.activation_map_combo.currentIndexChanged.connect(self.adjust_slider)
        self.activation_map_window.addWidget(self.activation_map_combo)

        self.image_settings_main_window.addLayout(self.image_settings_second_window)
        self.image_settings_main_window.addLayout(self.light_channel_layout)
        # self.image_settings_main_window.addWidget(self.activation_map_checkbox)
        self.image_settings_main_window.addLayout(self.activation_map_window)

        self.roi_buttons = QStackedLayout()

        self.roi_layout1 = QHBoxLayout()
        self.roi_layout1.setAlignment(Qt.AlignLeft)
        self.roi_layout1.setAlignment(Qt.AlignTop)
        self.roi_layout1.setContentsMargins(0, 0, 0, 0)
        self.reset_roi_button = QPushButton()
        self.reset_roi_button.setText("Reset ROI")
        self.reset_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-out-area.png"))
        )
        # self.reset_roi_button.setIcon(QIcon("gui/icons/zoom-out-area.png"))
        self.reset_roi_button.setEnabled(False)
        self.reset_roi_button.clicked.connect(self.reset_roi)
        self.roi_layout1.addWidget(self.reset_roi_button)

        self.set_roi_button = QPushButton()
        self.set_roi_button.setText("Set ROI")
        self.set_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-in-area.png"))
        )
        self.set_roi_button.clicked.connect(self.set_roi)
        self.roi_layout1.addWidget(self.set_roi_button)
        self.roi_layout1_container = QWidget()
        self.roi_layout1_container.setLayout(self.roi_layout1)

        self.roi_layout2 = QHBoxLayout()
        self.roi_layout2.setAlignment(Qt.AlignLeft)
        self.roi_layout2.setAlignment(Qt.AlignTop)
        self.roi_layout2.setContentsMargins(0, 0, 0, 0)
        self.cancel_roi_button = QPushButton()
        self.cancel_roi_button.setText("Cancel")
        self.cancel_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-cancel.png"))
        )
        self.cancel_roi_button.clicked.connect(self.cancel_roi)
        self.roi_layout2.addWidget(self.cancel_roi_button)

        self.save_roi_button = QPushButton()
        self.save_roi_button.setText("Save ROI")
        self.save_roi_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-check.png"))
        )
        self.save_roi_button.clicked.connect(self.save_roi)
        self.roi_layout2.addWidget(self.save_roi_button)
        self.roi_layout2_container = QWidget()
        self.roi_layout2_container.setLayout(self.roi_layout2)

        if self.acquisition_mode:
            self.roi_buttons.addWidget(self.roi_layout1_container)
            self.roi_buttons.addWidget(self.roi_layout2_container)
            self.image_settings_main_window.addLayout(self.roi_buttons)

        self.exposure_slider = QSlider(Qt.Horizontal, self)
        self.exposure_slider.setRange(0, 4096)
        self.exposure_slider.setValue(4096)
        self.exposure_slider.valueChanged.connect(self.adjust_exposure)
        self.image_settings_main_window.addWidget(self.exposure_slider)
        self.image_settings_main_window.addStretch()

        self.activate_live_preview_button = QPushButton()
        self.activate_live_preview_button.setText("Start Live Preview")
        self.activate_live_preview_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "video.png"))
        )
        self.activate_live_preview_button.clicked.connect(self.open_live_preview_thread)

        self.deactivate_live_preview_button = QPushButton()
        self.deactivate_live_preview_button.setText("Stop Live Preview")
        self.deactivate_live_preview_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "video-off.png"))
        )
        self.deactivate_live_preview_button.clicked.connect(self.stop_live)

        self.image_settings_main_window.addStretch()

        if self.acquisition_mode:
            self.grid_layout.addLayout(self.image_settings_main_window, 1, 1)

        self.live_preview_label = QLabel("Live Preview")
        self.live_preview_label.setFont(QFont("IBM Plex Sans", 17))
        self.image_view = PlotWindow()
        self.plot_image = plt.imshow(
            np.zeros(
                (int(1024 / self.config["Binning"]), int(1024 / self.config["Binning"]))
            ),
            cmap="binary_r",
            vmin=0,
            vmax=4096,
            origin="lower",
        )
        self.plot_image.axes.get_xaxis().set_visible(False)
        self.plot_image.axes.axes.get_yaxis().set_visible(False)

        if self.acquisition_mode:
            self.grid_layout.addWidget(self.live_preview_label, 0, 2)
            self.grid_layout.addWidget(self.image_view, 1, 2)

        self.tree_label = QLabel("Stimulation Tree")
        self.tree_label.setFont(QFont("IBM Plex Sans", 17))
        self.grid_layout.addWidget(self.tree_label, 2, 0)

        self.tree_window = QVBoxLayout()
        self.tree = Tree()
        self.tree.setHeaderLabels(
            [
                "0 Name",
                "1 Iterations",
                "2 Delay",
                "3 Jitter",
                "4 Type",
                "5 Pulses",
                "6 Duration",
                "7 Jitter",
                "8 Width",
                "9 Frequency",
                "10 Duty",
                "11 Type2",
                "12 Pulses 2",
                "13 Jitter 2",
                "14 Width 2",
                "15 Frequency 2",
                "16 Duty 2",
                "17 Baseline",
                "18 Canal 1",
                "19 Canal 2",
                "20 Valid",
                "21 Heigth",
                "22 Heigth 2",
                "23 Type 3",
                "24 Pulses 3",
                "25 Jitter 3",
                "26 Width 3",
                "27 Frequency 3",
                "28 Duty 3",
                "29 Heigth 3",
                "30 Canal 3",
            ]
        )
        if not self.config["Debug"]:
            for i in range(1, 20):
                self.tree.header().hideSection(i)
            for i in range(21, 31):
                self.tree.header().hideSection(i)
            self.tree.setHeaderHidden(True)
            self.tree.header().setSectionResizeMode(0, QHeaderView.Stretch)
            self.tree.header().setStretchLastSection(False)
        self.tree.currentItemChanged.connect(self.actualize_window)
        self.tree_window.addWidget(self.tree)

        self.tree_switch_window = QStackedLayout()
        self.tree_second_window = QHBoxLayout()
        self.stim_buttons_container = QWidget()
        self.delete_item_button = QPushButton("Delete")
        self.delete_item_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "trash.png"))
        )
        self.delete_item_button.clicked.connect(self.tree.delete_item)
        self.tree_second_window.addWidget(self.delete_item_button)
        self.add_brother_branch_button = QPushButton("Add Sibling")
        self.add_brother_branch_button.clicked.connect(self.tree.add_brother)
        self.add_brother_branch_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "arrow-bar-down.png"))
        )
        self.tree_second_window.addWidget(self.add_brother_branch_button)
        self.add_child_branch_button = QPushButton("Add Child")
        self.add_child_branch_button.clicked.connect(self.tree.add_child)
        self.add_child_branch_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "arrow-bar-right.png"))
        )
        self.tree_second_window.addWidget(self.add_child_branch_button)
        self.stim_buttons_container.setLayout(self.tree_second_window)
        self.tree_switch_window.addWidget(self.stim_buttons_container)

        self.tree_third_window = QHBoxLayout()
        self.import_button = QPushButton("Import Configuration")
        self.import_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "packge-import.png"))
        )
        self.import_button.clicked.connect(self.import_config)
        self.tree_third_window.addWidget(self.import_button)
        self.new_branch_button = QPushButton("New Stimulation")
        self.new_branch_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "square-plus.png"))
        )
        self.tree_third_window.addWidget(self.new_branch_button)
        self.stim_buttons_container2 = QWidget()
        self.stim_buttons_container2.setLayout(self.tree_third_window)
        self.tree_switch_window.addWidget(self.stim_buttons_container2)
        self.new_branch_button.clicked.connect(self.tree.first_stimulation)
        self.grid_layout.addLayout(self.tree_switch_window, 4, 0)

        self.tree_switch_window.setCurrentIndex(1)
        self.grid_layout.addLayout(self.tree_window, 3, 0)

        self.signal_adjust_label = QLabel("Signal Adjust")
        self.signal_adjust_label.setFont(QFont("IBM Plex Sans", 17))
        self.grid_layout.addWidget(self.signal_adjust_label, 2, 1)

        self.signal_adjust_superposed = QStackedLayout()
        self.stimulation_edit_layout = QVBoxLayout()
        self.stimulation_edit_layout.setContentsMargins(0, 0, 0, 0)

        self.canal_window = QVBoxLayout()
        self.canal_window.setAlignment(Qt.AlignLeft)
        self.canal_window.setAlignment(Qt.AlignTop)
        self.canal_window.setContentsMargins(0, 0, 0, 0)

        self.first_canal_check = QCheckBox()
        self.first_canal_check.stateChanged.connect(self.canals_to_tree)
        self.first_canal_check.setText("Canal 1")

        self.stim_type_cell = QComboBox()
        self.stim_type_cell.addItem("square")
        self.stim_type_cell.addItem("random-square")
        self.stim_type_cell.addItem("Third")
        self.stim_type_cell.currentIndexChanged.connect(self.type_to_tree)
        self.stimulation_type_window = QHBoxLayout()
        self.stimulation_type_window.addWidget(self.first_canal_check)
        self.stimulation_type_window.addWidget(self.stim_type_cell)
        self.canal_window.addLayout(self.stimulation_type_window)

        self.different_signals_window = QStackedLayout()
        self.canal_window.addLayout(self.different_signals_window)

        self.second_canal_check = QCheckBox()
        self.second_canal_check.stateChanged.connect(self.canals_to_tree)
        self.second_canal_check.setText("Canal 2")

        self.stim_type_cell2 = QComboBox()
        self.stim_type_cell2.addItem("square")
        self.stim_type_cell2.addItem("random-square")
        self.stim_type_cell2.addItem("Third")
        self.stim_type_cell2.currentIndexChanged.connect(self.type_to_tree)
        self.stimulation_type_window2 = QHBoxLayout()
        self.stimulation_type_window2.addWidget(self.second_canal_check)
        self.stimulation_type_window2.addWidget(self.stim_type_cell2)
        self.canal_window.addLayout(self.stimulation_type_window2)

        self.different_signals_window2 = QStackedLayout()
        self.canal_window.addLayout(self.different_signals_window2)

        self.third_canal_check = QCheckBox()
        self.third_canal_check.stateChanged.connect(self.canals_to_tree)
        self.third_canal_check.setText("Canal 3")
        # self.canal_window.addWidget(self.third_canal_check)

        self.stim_type_cell3 = QComboBox()
        self.stim_type_cell3.addItem("square")
        self.stim_type_cell3.addItem("random-square")
        self.stim_type_cell3.addItem("Third")
        self.stim_type_cell3.currentIndexChanged.connect(self.type_to_tree)
        self.stimulation_type_window3 = QHBoxLayout()
        self.stimulation_type_window3.addWidget(self.third_canal_check)
        # self.stimulation_type_window3.addWidget(self.stim_type_cell3)
        self.canal_window.addLayout(self.stimulation_type_window3)

        self.different_signals_window3 = QStackedLayout()
        self.canal_window.addLayout(self.different_signals_window3)

        self.stimulation_name_label = QLabel("Stimulation Name")
        self.stimulation_name_cell = QLineEdit()
        self.stimulation_name_cell.textEdited.connect(self.name_to_tree)
        self.stimulation_name_window = QHBoxLayout()
        self.stimulation_name_window.addWidget(self.stimulation_name_label)
        self.stimulation_name_window.addWidget(self.stimulation_name_cell)
        self.stimulation_edit_layout.addLayout(self.stimulation_name_window)

        self.duration_window = QHBoxLayout()
        self.first_signal_type_duration_label = QLabel("Duration (s)")
        self.duration_window.addWidget(self.first_signal_type_duration_label)
        self.duration_cell = QLineEdit()
        self.duration_window.addWidget(self.duration_cell)
        self.duration_cell.setValidator(self.onlyFloat)
        self.duration_cell.textEdited.connect(self.signal_to_tree)
        self.stimulation_edit_layout.addLayout(self.duration_window)

        self.baseline_checkbox = QCheckBox("Baseline")
        self.baseline_checkbox.stateChanged.connect(self.canals_to_tree)
        if self.acquisition_mode:
            self.stimulation_edit_layout.addWidget(self.baseline_checkbox)
        self.stimulation_edit_layout.addLayout(self.canal_window)

        self.first_signal_type_window = QVBoxLayout()
        self.first_signal_type_window.setAlignment(Qt.AlignLeft)
        self.first_signal_type_window.setAlignment(Qt.AlignTop)
        self.first_signal_type_window.setContentsMargins(0, 0, 0, 0)
        self.first_signal_type_container = QWidget()
        self.first_signal_type_container.setLayout(self.first_signal_type_window)

        self.first_signal_type_window2 = QVBoxLayout()
        self.first_signal_type_window2.setAlignment(Qt.AlignLeft)
        self.first_signal_type_window2.setAlignment(Qt.AlignTop)
        self.first_signal_type_window2.setContentsMargins(0, 0, 0, 0)
        self.first_signal_type_container2 = QWidget()
        self.first_signal_type_container2.setLayout(self.first_signal_type_window2)

        self.first_signal_type_window3 = QVBoxLayout()
        self.first_signal_type_window3.setAlignment(Qt.AlignLeft)
        self.first_signal_type_window3.setAlignment(Qt.AlignTop)
        self.first_signal_type_window3.setContentsMargins(0, 0, 0, 0)
        self.first_signal_type_container3 = QWidget()
        self.first_signal_type_container3.setLayout(self.first_signal_type_window3)

        self.pulses_window = QHBoxLayout()
        self.pulses_label = QLabel("Pulses")
        self.pulses_window.addWidget(self.pulses_label)
        self.pulses_cell = QLineEdit()
        self.pulses_cell.setValidator(QIntValidator())
        self.pulses_cell.textEdited.connect(self.signal_to_tree)
        self.pulses_window.addWidget(self.pulses_cell)

        self.pulses_window2 = QHBoxLayout()
        self.pulses_label2 = QLabel("Pulses")
        self.pulses_window2.addWidget(self.pulses_label2)
        self.pulses_cell2 = QLineEdit()
        self.pulses_cell2.setValidator(QIntValidator())
        self.pulses_cell2.textEdited.connect(self.signal_to_tree)
        self.pulses_window2.addWidget(self.pulses_cell2)

        self.pulses_window3 = QHBoxLayout()
        self.pulses_label3 = QLabel("Pulses")
        self.pulses_window3.addWidget(self.pulses_label3)
        self.pulses_cell3 = QLineEdit()
        self.pulses_cell3.setValidator(QIntValidator())
        self.pulses_cell3.textEdited.connect(self.signal_to_tree)
        self.pulses_window3.addWidget(self.pulses_cell3)

        self.jitter_window = QHBoxLayout()
        self.jitter_label = QLabel("Jitter (s)")
        self.jitter_window.addWidget(self.jitter_label)
        self.jitter_cell = QLineEdit()
        self.jitter_cell.setValidator(self.onlyFloat)
        self.jitter_cell.setText("0")
        self.jitter_cell.textEdited.connect(self.signal_to_tree)
        self.jitter_window.addWidget(self.jitter_cell)

        self.jitter_window2 = QHBoxLayout()
        self.jitter_window2 = QHBoxLayout()
        self.jitter_label2 = QLabel("Jitter (s)")
        self.jitter_window2.addWidget(self.jitter_label2)
        self.jitter_cell2 = QLineEdit()
        self.jitter_cell2.setValidator(self.onlyFloat)
        self.jitter_cell2.setText("0")
        self.jitter_cell2.textEdited.connect(self.signal_to_tree)
        self.jitter_window2.addWidget(self.jitter_cell2)

        self.jitter_window3 = QHBoxLayout()
        self.jitter_window3 = QHBoxLayout()
        self.jitter_label3 = QLabel("Jitter (s)")
        self.jitter_window3.addWidget(self.jitter_label3)
        self.jitter_cell3 = QLineEdit()
        self.jitter_cell3.setValidator(self.onlyFloat)
        self.jitter_cell3.setText("0")
        self.jitter_cell3.textEdited.connect(self.signal_to_tree)
        self.jitter_window3.addWidget(self.jitter_cell3)

        self.width_window = QHBoxLayout()
        self.width_label = QLabel("Width (s)")
        self.width_window.addWidget(self.width_label)
        self.width_cell = QLineEdit()
        self.width_cell.setValidator(self.onlyFloat)
        self.width_cell.setText("0")
        self.width_cell.textEdited.connect(self.signal_to_tree)
        self.width_window.addWidget(self.width_cell)

        self.width_window2 = QHBoxLayout()
        self.width_label2 = QLabel("Width (s)")
        self.width_window2.addWidget(self.width_label2)
        self.width_cell2 = QLineEdit()
        self.width_cell2.setValidator(self.onlyFloat)
        self.width_cell2.setText("0")
        self.width_cell2.textEdited.connect(self.signal_to_tree)
        self.width_window2.addWidget(self.width_cell2)

        self.width_window3 = QHBoxLayout()
        self.width_label3 = QLabel("Width (s)")
        self.width_window3.addWidget(self.width_label3)
        self.width_cell3 = QLineEdit()
        self.width_cell3.setValidator(self.onlyFloat)
        self.width_cell3.setText("0")
        self.width_cell3.textEdited.connect(self.signal_to_tree)
        self.width_window3.addWidget(self.width_cell3)

        self.first_signal_type_window.addLayout(self.pulses_window)
        self.first_signal_type_window.addLayout(self.width_window)
        self.first_signal_type_window.addLayout(self.jitter_window)

        self.first_signal_type_window2.addLayout(self.pulses_window2)
        self.first_signal_type_window2.addLayout(self.width_window2)
        self.first_signal_type_window2.addLayout(self.jitter_window2)

        self.first_signal_type_window3.addLayout(self.pulses_window3)
        self.first_signal_type_window3.addLayout(self.width_window3)
        self.first_signal_type_window3.addLayout(self.jitter_window3)
        # -------------------

        self.second_signal_type_window = QVBoxLayout()
        self.second_signal_type_container = QWidget()
        self.second_signal_type_window.setAlignment(Qt.AlignLeft)
        self.second_signal_type_window.setAlignment(Qt.AlignTop)
        self.second_signal_type_window.setContentsMargins(0, 0, 0, 0)
        self.second_signal_type_container.setLayout(self.second_signal_type_window)
        # self.stimulation_edit_layout.addLayout(self.different_signals_window)

        self.second_signal_type_window2 = QVBoxLayout()
        self.second_signal_type_container2 = QWidget()
        self.second_signal_type_window2.setAlignment(Qt.AlignLeft)
        self.second_signal_type_window2.setAlignment(Qt.AlignTop)
        self.second_signal_type_window2.setContentsMargins(0, 0, 0, 0)
        self.second_signal_type_container2.setLayout(self.second_signal_type_window2)

        self.second_signal_type_window3 = QVBoxLayout()
        self.second_signal_type_container3 = QWidget()
        self.second_signal_type_window3.setAlignment(Qt.AlignLeft)
        self.second_signal_type_window3.setAlignment(Qt.AlignTop)
        self.second_signal_type_window3.setContentsMargins(0, 0, 0, 0)
        self.second_signal_type_container3.setLayout(self.second_signal_type_window3)

        self.heigth_window = QHBoxLayout()
        self.heigth_label = QLabel("Heigth (V)")
        self.heigth_window.addWidget(self.heigth_label)
        self.heigth_cell = QLineEdit()
        self.heigth_cell.setValidator(self.onlyFloat)
        self.heigth_cell.textEdited.connect(self.signal_to_tree)
        self.heigth_window.addWidget(self.heigth_cell)

        self.heigth_window2 = QHBoxLayout()
        self.heigth_label2 = QLabel("Heigth (V)")
        self.heigth_window2.addWidget(self.heigth_label2)
        self.heigth_cell2 = QLineEdit()
        self.heigth_cell2.setValidator(self.onlyFloat)
        self.heigth_cell2.textEdited.connect(self.signal_to_tree)
        self.heigth_window2.addWidget(self.heigth_cell2)

        self.heigth_window3 = QHBoxLayout()
        self.heigth_label3 = QLabel("Heigth (V)")
        self.heigth_window3.addWidget(self.heigth_label3)
        self.heigth_cell3 = QLineEdit()
        self.heigth_cell3.setValidator(self.onlyFloat)
        self.heigth_cell3.textEdited.connect(self.signal_to_tree)
        self.heigth_window3.addWidget(self.heigth_cell3)

        self.frequency_window = QHBoxLayout()
        self.frequency_label = QLabel("Frequency (Hz)")
        self.frequency_window.addWidget(self.frequency_label)
        self.frequency_cell = QLineEdit()
        self.frequency_cell.setValidator(self.onlyFloat)
        self.frequency_cell.textEdited.connect(self.signal_to_tree)
        self.frequency_window.addWidget(self.frequency_cell)

        self.frequency_window2 = QHBoxLayout()
        self.frequency_label2 = QLabel("Frequency (Hz)")
        self.frequency_window2.addWidget(self.frequency_label2)
        self.frequency_cell2 = QLineEdit()
        self.frequency_cell2.setValidator(self.onlyFloat)
        self.frequency_cell2.textEdited.connect(self.signal_to_tree)
        self.frequency_window2.addWidget(self.frequency_cell2)

        self.frequency_window3 = QHBoxLayout()
        self.frequency_label3 = QLabel("Frequency (Hz)")
        self.frequency_window3.addWidget(self.frequency_label3)
        self.frequency_cell3 = QLineEdit()
        self.frequency_cell3.setValidator(self.onlyFloat)
        self.frequency_cell3.textEdited.connect(self.signal_to_tree)
        self.frequency_window3.addWidget(self.frequency_cell3)

        self.duty_window = QHBoxLayout()
        self.duty_label = QLabel("Duty (%)")
        self.duty_window.addWidget(self.duty_label)
        self.duty_cell = QLineEdit()
        self.duty_cell.setValidator(self.onlyFloat)
        self.duty_cell.textEdited.connect(self.signal_to_tree)
        self.duty_window.addWidget(self.duty_cell)

        self.duty_window2 = QHBoxLayout()
        self.duty_label2 = QLabel("Duty (%)")
        self.duty_window2.addWidget(self.duty_label2)
        self.duty_cell2 = QLineEdit()
        self.duty_cell2.setValidator(self.onlyFloat)
        self.duty_cell2.textEdited.connect(self.signal_to_tree)
        self.duty_window2.addWidget(self.duty_cell2)

        self.duty_window3 = QHBoxLayout()
        self.duty_label3 = QLabel("Duty (%)")
        self.duty_window3.addWidget(self.duty_label3)
        self.duty_cell3 = QLineEdit()
        self.duty_cell3.setValidator(self.onlyFloat)
        self.duty_cell3.textEdited.connect(self.signal_to_tree)
        self.duty_window3.addWidget(self.duty_cell3)

        self.second_signal_type_window.addLayout(self.heigth_window)
        self.second_signal_type_window.addLayout(self.frequency_window)
        self.second_signal_type_window.addLayout(self.duty_window)

        self.second_signal_type_window2.addLayout(self.heigth_window2)
        self.second_signal_type_window2.addLayout(self.frequency_window2)
        self.second_signal_type_window2.addLayout(self.duty_window2)

        # self.second_signal_type_window3.addLayout(self.heigth_window3)
        self.second_signal_type_window3.addLayout(self.frequency_window3)
        self.second_signal_type_window3.addLayout(self.duty_window3)

        # -------------------

        self.third_signal_type_window = QVBoxLayout()
        self.third_signal_type_container = QWidget()
        self.third_signal_type_container.setLayout(self.third_signal_type_window)

        self.third_signal_type_window2 = QVBoxLayout()
        self.third_signal_type_container2 = QWidget()
        self.third_signal_type_container2.setLayout(self.third_signal_type_window2)

        self.third_signal_type_window3 = QVBoxLayout()
        self.third_signal_type_container3 = QWidget()
        self.third_signal_type_container3.setLayout(self.third_signal_type_window3)

        self.third_signal_type_name = QLabel("signal3")
        self.third_signal_type_window.addWidget(self.third_signal_type_name)

        self.third_signal_type_name2 = QLabel("signal3")
        self.third_signal_type_window2.addWidget(self.third_signal_type_name2)

        self.third_signal_type_name3 = QLabel("signal3")
        self.third_signal_type_window3.addWidget(self.third_signal_type_name3)

        self.different_signals_window.addWidget(self.second_signal_type_container)
        self.different_signals_window.addWidget(self.first_signal_type_container)
        self.different_signals_window.addWidget(self.third_signal_type_container)

        self.different_signals_window2.addWidget(self.second_signal_type_container2)
        self.different_signals_window2.addWidget(self.first_signal_type_container2)
        self.different_signals_window2.addWidget(self.third_signal_type_container2)

        self.different_signals_window3.addWidget(self.second_signal_type_container3)
        self.different_signals_window3.addWidget(self.first_signal_type_container3)
        self.different_signals_window3.addWidget(self.third_signal_type_container3)

        self.stimulation_edit_container = QWidget()
        self.stimulation_edit_container.setLayout(self.stimulation_edit_layout)
        self.block_edit_layout = QVBoxLayout()
        self.block_edit_layout.setContentsMargins(0, 0, 0, 0)
        self.block_edit_layout.setAlignment(Qt.AlignLeft)
        self.block_edit_layout.setAlignment(Qt.AlignTop)

        self.block_name_label = QLabel("Block Name")
        self.block_name_cell = QLineEdit()
        self.block_name_cell.textEdited.connect(self.name_to_tree)
        self.block_name_window = QHBoxLayout()
        self.block_name_window.addWidget(self.block_name_label)
        self.block_name_window.addWidget(self.block_name_cell)
        self.block_edit_layout.addLayout(self.block_name_window)

        self.block_iterations_window = QHBoxLayout()
        self.block_iterations_label = QLabel("Iterations")
        self.block_iterations_cell = QLineEdit()
        self.block_iterations_cell.setValidator(QIntValidator())
        self.block_iterations_cell.textEdited.connect(self.block_to_tree)
        self.block_iterations_window.addWidget(self.block_iterations_label)
        self.block_iterations_window.addWidget(self.block_iterations_cell)
        self.block_edit_layout.addLayout(self.block_iterations_window)

        self.block_delay_window = QHBoxLayout()
        self.block_delay_label = QLabel("Delay")
        self.block_delay_cell = QLineEdit()
        self.block_delay_cell.setValidator(self.onlyFloat)
        self.block_delay_cell.textEdited.connect(self.block_to_tree)
        self.block_delay_window = QHBoxLayout()
        self.block_delay_window.addWidget(self.block_delay_label)
        self.block_delay_window.addWidget(self.block_delay_cell)
        self.block_edit_layout.addLayout(self.block_delay_window)

        self.block_jitter_window = QHBoxLayout()
        self.block_jitter_label = QLabel("Jitter")
        self.block_jitter_cell = QLineEdit()
        self.block_jitter_cell.setValidator(self.onlyFloat)
        self.block_jitter_cell.textEdited.connect(self.block_to_tree)
        self.block_jitter_window = QHBoxLayout()
        self.block_jitter_window.addWidget(self.block_jitter_label)
        self.block_jitter_window.addWidget(self.block_jitter_cell)
        self.block_edit_layout.addLayout(self.block_jitter_window)

        self.block_edit_container = QWidget()
        self.block_edit_container.setLayout(self.block_edit_layout)
        self.signal_adjust_superposed.addWidget(self.stimulation_edit_container)
        self.signal_adjust_superposed.addWidget(self.block_edit_container)
        self.signal_adjust_superposed.addWidget(QLabel())
        self.signal_adjust_superposed.setCurrentIndex(2)
        self.grid_layout.addLayout(self.signal_adjust_superposed, 3, 1)

        self.signal_preview_label = QLabel("Signal Preview")
        self.signal_preview_label.setFont(QFont("IBM Plex Sans", 17))
        if self.acquisition_mode:
            self.grid_layout.addWidget(self.signal_preview_label, 2, 2)
        else:
            self.grid_layout.addWidget(self.signal_preview_label, 0, 2)

        self.buttons_main_window = QHBoxLayout()
        self.stop_button = QPushButton("Stop")
        self.stop_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "player-stop.png"))
        )
        self.stop_button.clicked.connect(self.stop_while_running)
        self.stop_button.setEnabled(False)
        self.buttons_main_window.addWidget(self.stop_button)
        self.run_button = QPushButton("Run")
        self.run_button.setIcon(
            QIcon(os.path.join(self.cwd, "gui", "icons", "player-play.png"))
        )
        self.run_button.clicked.connect(self.run)
        self.run_button.setEnabled(False)
        self.buttons_main_window.addWidget(self.run_button)
        self.plot_window = PlotWindow(subplots=True)
        if self.acquisition_mode:
            self.grid_layout.addWidget(self.plot_window, 3, 2)
        else:
            self.grid_layout.addWidget(self.plot_window, 1, 2, 3, 1)
        self.grid_layout.addLayout(self.buttons_main_window, 4, 2)
        self.open_daq_generation_thread()
        self.initialize_buttons()
        self.show()

    def deactivate_channels(self):
        """Deactivate canal checkboxes if the baseline checkbox is checked"""
        if self.baseline_checkbox.isChecked():
            self.deactivate_buttons(
                [
                    self.first_canal_check,
                    self.second_canal_check,
                ]
            )
        else:
            self.activate_buttons(
                [
                    self.first_canal_check,
                    self.second_canal_check,
                ]
            )

    def adjust_exposure(self):
        """Match the exposure of the image preview to the slider value"""
        self.max_exposure = self.exposure_slider.value()
        self.slider_values[self.preview_light_combo.currentText()][
            self.activation_map_combo.currentText()
        ] = self.max_exposure

    def set_trigger(self):
        """Set the trigger for the DAQ"""
        if not self.acquisition_mode:
            self.run_button.setText("Run at Trigger")
            self.daq.set_trigger(self.ports["trigger"])
        else:
            self.run_button.setText("Run")
            self.daq.remove_trigger()

    def import_config(self):
        """Import a configuration file"""
        file = QFileDialog.getOpenFileName()[0]
        try:
            dictionary = get_dictionary(file)
            self.framerate_cell.setText(str(dictionary["Framerate"]))
            self.exposure_cell.setText(str(dictionary["Exposition"]))
            self.set_lights(dictionary["Lights"])
            self.tree.create_tree_item(dictionary["Blocks"])
            self.enable_run(self.tree.check_global_validity())
            self.tree.graph(self.tree.invisibleRootItem())
            self.draw()
        except Exception as err:
            print(err)

    def set_lights(self, lights):
        """Set the lights"""
        for light in lights:
            if light == "infrared":
                self.ir_checkbox.setChecked(True)
            elif light == "red":
                self.red_checkbox.setChecked(True)
            elif light == "green":
                self.green_checkbox.setChecked(True)
            elif light == "blue":
                self.fluorescence_checkbox.setChecked(True)

    def run(self):
        """Run the experiment"""
        if self.check_override():
            self.deactivate_buttons(buttons=self.enabled_buttons)
            self.master_block = self.tree.create_blocks()
            self.tree.baseline_values = []
            self.tree.graph(item=self.tree.invisibleRootItem())
            self.root_time, self.root_signal = (
                self.tree.x_values,
                [
                    self.tree.stim1_values,
                    self.tree.stim2_values,
                    self.tree.stim3_values,
                ],
            )
            self.draw(root=True)
            if self.acquisition_mode:
                self.actualize_daq()
                self.open_live_saving_thread()
                self.open_live_preview_thread()
                self.open_baseline_check_thread()
            else:
                self.daq.stop_signal = False
            self.open_signal_preview_thread()
            self.open_start_experiment_thread()

    def check_override(self):
        """Check if experiment with the same name already exists"""
        if os.path.isfile(
            os.path.join(
                self.directory_cell.text(),
                self.experiment_name_cell.text(),
                f"{self.experiment_name_cell.text()}-light_signal.npy",
            )
        ):
            button = QMessageBox.question(
                self,
                "Files already exist",
                "Files already exist. \n Do you want to override the existing files?",
            )
            if button == QMessageBox.Yes:
                return True
            else:
                return False
        else:
            return True

    def open_baseline_check_thread(self):
        """Open the thread for the baseline check"""
        self.baseline_check_thread = Thread(target=self.check_baseline)
        self.baseline_check_thread.start()

    def check_baseline(self):
        """Monitor the incoming frames and check if the baseline is reached"""
        if len(self.daq.lights) > 0:
            self.camera.baseline_data = []
            self.camera.adding_frames = False
            self.camera.completed_baseline = False
            while self.daq.camera_signal is None:
                pass
            frames_acquired = frames_acquired_from_camera_signal(self.daq.camera_signal)
            baseline_indices = get_baseline_frame_indices(
                self.tree.baseline_values, frames_acquired
            )
            for baseline_pair in baseline_indices:
                while not self.daq.stop_signal:
                    try:
                        if (
                            not self.camera.adding_frames
                            and self.camera.frames_read >= baseline_pair[0]
                        ):
                            self.camera.adding_frames = True
                        elif (
                            self.camera.adding_frames
                            and self.camera.frames_read >= baseline_pair[1]
                        ):
                            self.camera.baseline_read_list = []
                            self.camera.average_baseline = average_baseline(
                                self.camera.baseline_data,
                                len(self.daq.lights),
                                self.camera.frames_read_list[0] % len(self.daq.lights),
                            )
                            self.camera.adding_frames = False
                            self.camera.baseline_frames = []
                            self.camera.baseline_completed = True
                            self.camera.frames_read_list = []
                            break
                    except Exception as err:
                        pass
                    time.sleep(0.01)

    def open_start_experiment_thread(self):
        """Open the thread for the start of the experiment"""
        self.start_experiment_thread = Thread(target=self.run_stimulation)
        self.start_experiment_thread.start()

    def save_config(self):
        """Save the current configuration to a JSON file"""
        folder = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        if folder != "":
            self.master_block = self.tree.create_blocks()
            self.experiment = Experiment(
                self.master_block,
                int(self.framerate_cell.text()),
                int(self.exposure_cell.text()),
                self.mouse_id_cell.text(),
                folder,
                self.daq,
                name=self.experiment_name_cell.text(),
                config=self.config,
            )
            self.experiment.save_config(
                [int(1024 / self.config["Binning"]), int(1024 / self.config["Binning"])]
            )

    def run_stimulation(self):
        """Run the stimulation in parallel with the lights"""
        self.experiment = Experiment(
            self.master_block,
            int(self.framerate_cell.text()),
            int(self.exposure_cell.text()),
            self.mouse_id_cell.text(),
            self.directory_cell.text(),
            self.daq,
            name=self.experiment_name_cell.text(),
            config=self.config,
        )
        self.save_files_after_stop = True
        self.daq.launch(self.experiment.name, self.root_time, self.root_signal)
        # if (
        #    not self.daq.stop_signal
        #    and self.save_files_after_stop
        #    and self.directory_save_files_checkbox.isChecked()
        # ):
        if (
            self.save_files_after_stop
            and self.directory_save_files_checkbox.isChecked()
        ):
            try:
                print("this is the extent")
                print(self.roi_extent)
                self.experiment.save(self.roi_extent)
            except Exception as err:
                print("err after saving first")
                print(err)
                print("err before entering")
                self.experiment.save()
        self.stop()

    def open_live_saving_thread(self):
        """Open the thread for the live saving"""
        self.live_save_thread = Thread(target=self.live_save)
        self.live_save_thread.start()

    def live_save(self):
        """Save NPY chunked files when the number of frames is over 1200"""
        self.camera.file_index = 0
        self.camera.is_saving = False
        if self.directory_save_files_checkbox.isChecked():
            try:
                os.mkdir(
                    os.path.join(
                        self.directory_cell.text(), self.experiment_name_cell.text()
                    )
                )
                os.mkdir(
                    os.path.join(
                        self.directory_cell.text(),
                        self.experiment_name_cell.text(),
                        "data",
                    )
                )
            except Exception as err:
                pass
            while self.camera.video_running is False and not self.camera.stop_signal:
                time.sleep(0.01)
                pass
            while self.camera.video_running is True:
                if len(self.camera.frames) > 1200:
                    self.memory = self.camera.frames[:1200]
                    self.camera.frames = self.camera.frames[1200:]
                    if self.directory_save_files_checkbox.isChecked():
                        try:
                            self.memory = shrink_array(self.memory, self.roi_extent)
                        except Exception:
                            pass
                        self.camera.is_saving = True
                        np.save(
                            os.path.join(
                                self.directory_cell.text(),
                                self.experiment_name_cell.text(),
                                "data",
                                f"{self.camera.file_index}.npy",
                            ),
                            self.memory,
                        )
                        self.memory = None
                        self.camera.file_index += 1
                        self.camera.is_saving = False
                time.sleep(0.01)

    def open_live_preview_thread(self):
        """Open the thread for the live preview"""
        self.live_preview_thread = Thread(target=self.start_live)
        self.live_preview_thread.start()

    def start_live(self):
        """Start the live preview"""
        plt.ion()
        self.memory = []
        self.camera.baseline_completed = False
        if len(self.daq.lights) > 0:
            try:
                while self.camera.video_running is False:
                    time.sleep(0.01)
                    pass
                while self.camera.video_running is True:
                    try:
                        if (
                            not self.camera.baseline_completed
                            or self.activation_map_combo.currentIndex() == 0
                        ):
                            self.plot_image.set(
                                array=self.camera.frames[
                                    self.live_preview_light_index :: len(
                                        self.daq.lights
                                    )
                                ][-1],
                                clim=(0, self.max_exposure),
                                cmap="binary_r",
                            )
                        elif self.activation_map_combo.currentIndex() == 1:
                            start_index = (
                                self.camera.baseline_read_list[0]
                                + self.live_preview_light_index
                            ) % len(self.daq.lights)
                            activation_map = (
                                self.camera.baseline_frames[
                                    start_index :: len(self.daq.lights)
                                ][-1]
                                - self.camera.average_baseline[
                                    self.live_preview_light_index
                                ]
                            ) / self.camera.average_baseline[
                                self.live_preview_light_index
                            ]
                            self.plot_image.set(
                                array=activation_map,
                                clim=(
                                    -self.max_exposure / 200,
                                    self.max_exposure / 200,
                                ),
                                cmap="seismic",
                            )
                        else:
                            start_index = (
                                self.camera.baseline_read_list[0]
                                + self.live_preview_light_index
                            ) % len(self.daq.lights)
                            activation_map = np.log(
                                (
                                    (
                                        self.camera.baseline_frames[
                                            start_index :: len(self.daq.lights)
                                        ][-1]
                                        - self.camera.average_baseline[
                                            self.live_preview_light_index
                                        ]
                                    )
                                    / self.camera.average_baseline[
                                        self.live_preview_light_index
                                    ]
                                )
                            )
                            self.plot_image.set(
                                array=activation_map,
                                clim=(
                                    -self.max_exposure / 2000,
                                    self.max_exposure / 2000,
                                ),
                                cmap="seismic",
                            )

                    except Exception as err:
                        print(err)
                        pass
                    time.sleep(0.04)
            except Exception as err:
                pass

    def stop_live(self):
        """Stop the live preview"""
        self.camera.video_running = False

    def open_signal_preview_thread(self):
        """Open the thread for the signal preview"""
        self.signal_preview_thread = Thread(target=self.actualize_progression)
        self.signal_preview_thread.start()

    def actualize_progression(self):
        """Actualize the position of the progress bar"""
        plt.ion()
        while self.daq.stop_signal is False:
            try:
                if self.acquisition_mode:
                    position = self.camera.frames_read / int(self.framerate_cell.text())
                else:
                    position = time.time() - self.daq.start_time
                self.plot_window.vertical_lines[0].set_xdata(position)
                self.plot_window.vertical_lines[1].set_xdata(position)
                self.plot_window.vertical_lines[2].set_xdata(position)
                time.sleep(0.5)
            except Exception as err:
                time.sleep(0.5)
                pass

    def change_preview_light_channel(self):
        """Change the light channel for the live preview"""
        self.live_preview_light_index = self.preview_light_combo.currentIndex()
        self.adjust_slider()

    def adjust_slider(self):
        """Adjust the saturation slider using corresponding value in dictionary"""
        try:
            value = self.slider_values[self.preview_light_combo.currentText()][
                self.activation_map_combo.currentText()
            ]
            self.exposure_slider.setValue(value)
        except Exception:
            pass

    def open_daq_generation_thread(self):
        """Open the thread for the DAQ generation"""
        self.daq_generation_thread = Thread(target=self.generate_daq)
        self.daq_generation_thread.start()

    def generate_daq(self):
        """Generate the DAQ"""
        try:
            self.camera = Camera(self.ports["camera"], "name")
        except Exception:
            self.camera = None
        self.stimuli = [
            Instrument(self.ports["analog0"], "air-pump"),
            Instrument(self.ports["analog1"], "air-pump2"),
            Instrument(self.ports["co2"], "air-pump3"),
        ]
        self.daq = DAQ(
            "dev1",
            [],
            self.stimuli,
            self.camera,
            int(self.framerate_cell.text()),
            int(self.exposure_cell.text()) / 1000,
        )
        self.daq.close_all_lights(self.ports)
        self.daq_generated = True
        self.enable_run(self.tree.check_global_validity())

    def actualize_daq(self):
        """Actualize the DAQ with the current settings"""
        try:
            self.daq.lights = []
            if self.ir_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["infrared"], "ir"))
            if self.red_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["red"], "red"))
            if self.green_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["green"], "green"))
            if self.fluorescence_checkbox.isChecked():
                self.daq.lights.append(Instrument(self.ports["blue"], "blue"))
            self.daq.framerate = int(self.framerate_cell.text())
            self.daq.exposure = int(self.exposure_cell.text()) / 1000
            self.camera.frames = []
            self.daq.stop_signal = False
        except Exception:
            pass

    def stop(self):
        """Stop the experiment and reactivate the interface"""
        self.stop_live()
        self.activate_buttons(buttons=self.enabled_buttons)
        self.tree.setCurrentItem(self.tree.topLevelItem(0))
        try:
            self.daq.stop_signal = True
        except Exception:
            pass

    def stop_while_running(self):
        """Stop the experiment while it is running"""
        if self.directory_save_files_checkbox.isChecked():
            self.stop_stimulation_dialog()
        self.stop()

    def stop_stimulation_dialog(self):
        """Ask if user wants to keep the files after experiment is stopped"""
        button = QMessageBox.question(
            self, "Save Files", "Do you want to save the current files?"
        )
        if button == QMessageBox.Yes:
            self.save_files_after_stop = True
        else:
            self.save_files_after_stop = False

    def show_buttons(self, buttons):
        """Show the buttons in a list"""
        for button in buttons:
            button.setVisible(True)

    def hide_buttons(self, buttons):
        """Hide the buttons in a list"""
        for button in buttons:
            button.setVisible(False)

    def activate_buttons(self, buttons):
        """Activate the buttons in a list"""
        for button in buttons:
            button.setEnabled(True)
        if buttons == self.enabled_buttons:
            if self.directory_save_files_checkbox.isChecked():
                self.directory_choose_button.setEnabled(True)
            if self.roi_extent is None:
                self.reset_roi_button.setEnabled(False)
            else:
                self.set_roi_button.setEnabled(False)
            self.stop_button.setDisabled(True)

    def deactivate_buttons(self, buttons):
        """Deactivate the buttons in a list"""
        if buttons == self.enabled_buttons:
            self.stop_button.setEnabled(True)
            self.tree.clearSelection()
        for button in buttons:
            button.setDisabled(True)

    def choose_directory(self):
        """Choose the directory where to save the files"""
        folder = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        self.directory_cell.setText(folder)

    def enable_directory(self):
        """Enable the directory cell"""
        self.files_saved = self.directory_save_files_checkbox.isChecked()
        self.directory_choose_button.setEnabled(self.files_saved)
        self.directory_cell.setEnabled(self.files_saved)

    def actualize_window(self):
        """Actualize the 'Stimulation Edit' and 'Signal Preview' windows"""
        self.activate_buttons(
            [self.add_child_branch_button, self.add_brother_branch_button]
        )
        if self.tree.currentItem():
            self.tree_switch_window.setCurrentIndex(0)
        else:
            self.tree_switch_window.setCurrentIndex(1)
        try:
            if self.tree.currentItem().childCount() > 0:
                self.signal_adjust_superposed.setCurrentIndex(1)
            else:
                self.signal_adjust_superposed.setCurrentIndex(0)
        except AttributeError:
            self.signal_adjust_superposed.setCurrentIndex(2)
        self.tree_to_name()
        self.tree_to_block()
        self.tree_to_type()
        self.tree_to_signal()
        self.tree_to_canal()
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()

    def name_to_tree(self):
        """Transfer the name of the current item from the cell to the tree"""
        branch = self.tree.currentItem()
        branch.setForeground(0, QBrush(QColor(0, 0, 0)))
        if branch.childCount() > 0:
            branch.setText(0, self.block_name_cell.text())
        else:
            branch.setText(0, self.stimulation_name_cell.text())

    def tree_to_name(self):
        """Transfer the name of the current item from the tree to the cell"""
        try:
            if self.tree.currentItem().childCount() > 0:
                if self.tree.currentItem().text(0) != "No Name":
                    self.block_name_cell.setText(self.tree.currentItem().text(0))
                else:
                    self.block_name_cell.setText("")
            else:
                if self.tree.currentItem().text(0) != "No Name":
                    self.stimulation_name_cell.setText(self.tree.currentItem().text(0))
                else:
                    self.stimulation_name_cell.setText("")
        except AttributeError:
            pass

    def type_to_tree(self):
        """Transfer the type of the current item from the cell to the tree"""
        self.enable_run(self.tree.check_global_validity())
        self.different_signals_window.setCurrentIndex(
            self.stim_type_cell.currentIndex()
        )
        self.different_signals_window2.setCurrentIndex(
            self.stim_type_cell2.currentIndex()
        )
        self.different_signals_window3.setCurrentIndex(
            self.stim_type_cell3.currentIndex()
        )
        try:
            self.tree.currentItem().setText(4, str(self.stim_type_cell.currentText()))
        except Exception:
            pass
        try:
            self.tree.currentItem().setText(11, str(self.stim_type_cell2.currentText()))
        except Exception:
            pass
        try:
            self.tree.currentItem().setText(23, str(self.stim_type_cell3.currentText()))
        except Exception:
            pass
        try:
            self.tree.graph(self.tree.currentItem(), current=True)
            self.draw()
        except Exception:
            pass

    def tree_to_type(self):
        """Transfer the type of the current item from the tree to the cell"""
        dico = {"square": 0, "random-square": 1, "Third": 2}
        try:
            self.stim_type_cell.setCurrentIndex(dico[self.tree.currentItem().text(4)])
        except Exception:
            self.stim_type_cell.setCurrentIndex(0)

        try:
            self.stim_type_cell2.setCurrentIndex(dico[self.tree.currentItem().text(11)])
        except Exception:
            self.stim_type_cell2.setCurrentIndex(0)

        try:
            self.stim_type_cell3.setCurrentIndex(dico[self.tree.currentItem().text(23)])
        except Exception:
            self.stim_type_cell3.setCurrentIndex(0)

    def signal_to_tree(self):
        """Transfer the signal of the current item from the cell to the tree"""
        self.tree.currentItem().setText(6, self.duration_cell.text())
        self.tree.currentItem().setText(5, self.pulses_cell.text())
        self.tree.currentItem().setText(7, self.jitter_cell.text())
        self.tree.currentItem().setText(8, self.width_cell.text())
        self.tree.currentItem().setText(9, self.frequency_cell.text())
        self.tree.currentItem().setText(10, self.duty_cell.text())
        self.tree.currentItem().setText(21, self.heigth_cell.text())
        self.tree.currentItem().setText(12, self.pulses_cell2.text())
        self.tree.currentItem().setText(13, self.jitter_cell2.text())
        self.tree.currentItem().setText(14, self.width_cell2.text())
        self.tree.currentItem().setText(15, self.frequency_cell2.text())
        self.tree.currentItem().setText(16, self.duty_cell2.text())
        self.tree.currentItem().setText(22, self.heigth_cell2.text())
        self.tree.currentItem().setText(24, self.pulses_cell3.text())
        self.tree.currentItem().setText(25, self.jitter_cell3.text())
        self.tree.currentItem().setText(26, self.width_cell3.text())
        self.tree.currentItem().setText(27, self.frequency_cell3.text())
        self.tree.currentItem().setText(28, self.duty_cell3.text())
        self.enable_run(self.tree.check_global_validity())
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()

    def tree_to_signal(self):
        """Transfer the signal of the current item from the tree to the cell"""
        try:
            self.pulses_cell.setText(self.tree.currentItem().text(5))
            self.duration_cell.setText(self.tree.currentItem().text(6))
            self.jitter_cell.setText(self.tree.currentItem().text(7))
            self.width_cell.setText(self.tree.currentItem().text(8))
            self.frequency_cell.setText(self.tree.currentItem().text(9))
            self.heigth_cell.setText(self.tree.currentItem().text(21))
            self.duty_cell.setText(self.tree.currentItem().text(10))
            self.pulses_cell2.setText(self.tree.currentItem().text(12))
            self.jitter_cell2.setText(self.tree.currentItem().text(13))
            self.width_cell2.setText(self.tree.currentItem().text(14))
            self.frequency_cell2.setText(self.tree.currentItem().text(15))
            self.heigth_cell2.setText(self.tree.currentItem().text(22))
            self.duty_cell2.setText(self.tree.currentItem().text(16))
            self.pulses_cell3.setText(self.tree.currentItem().text(24))
            self.jitter_cell3.setText(self.tree.currentItem().text(25))
            self.width_cell3.setText(self.tree.currentItem().text(26))
            self.frequency_cell3.setText(self.tree.currentItem().text(27))
            self.duty_cell3.setText(self.tree.currentItem().text(28))
        except Exception as err:
            pass

    def tree_to_block(self):
        """Transfer the block attributes from the tree to the cells"""
        try:
            self.block_iterations_cell.setText(self.tree.currentItem().text(1))
            self.block_delay_cell.setText(self.tree.currentItem().text(2))
            self.block_jitter_cell.setText(self.tree.currentItem().text(3))
        except Exception:
            pass

    def block_to_tree(self):
        """Transfer the block attributes from the cells to the tree"""
        self.tree.currentItem().setText(1, self.block_iterations_cell.text())
        self.tree.currentItem().setText(2, self.block_delay_cell.text())
        self.tree.currentItem().setText(3, self.block_jitter_cell.text())
        self.enable_run(self.tree.check_global_validity())
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()

    def tree_to_canal(self):
        """Transfer the canals attributes from the tree to the cells"""
        self.canal_running = True
        try:
            self.baseline_checkbox.setChecked(
                self.boolean(self.tree.currentItem().text(17))
            )
            self.first_canal_check.setChecked(
                self.boolean(self.tree.currentItem().text(18))
            )
            self.second_canal_check.setChecked(
                self.boolean(self.tree.currentItem().text(19))
            )
            self.third_canal_check.setChecked(
                self.boolean(self.tree.currentItem().text(30))
            )
            if self.baseline_checkbox.isChecked():
                self.deactivate_buttons(self.canal1buttons + [self.first_canal_check])
                self.deactivate_buttons(self.canal2buttons + [self.second_canal_check])
                self.deactivate_buttons(self.canal3buttons + [self.third_canal_check])
            else:
                self.activate_buttons(
                    [
                        self.first_canal_check,
                        self.second_canal_check,
                        self.third_canal_check,
                    ]
                )
            if self.first_canal_check.isChecked():
                self.activate_buttons(self.canal1buttons)
            else:
                self.deactivate_buttons(self.canal1buttons)
            if self.second_canal_check.isChecked():
                self.activate_buttons(self.canal2buttons)
            else:
                self.deactivate_buttons(self.canal2buttons)
            if self.third_canal_check.isChecked():
                self.activate_buttons(self.canal3buttons)
            else:
                self.deactivate_buttons(self.canal3buttons)
        except Exception as err:
            pass
        self.canal_running = False

    def canals_to_tree(self):
        """Transfer the canals attributes from the cells to the tree"""
        self.baseline_checkbox.setEnabled(True)
        if not self.canal_running:
            if self.baseline_checkbox.isChecked():
                self.deactivate_buttons(self.canal1buttons + [self.first_canal_check])
                self.deactivate_buttons(self.canal2buttons + [self.second_canal_check])
                self.deactivate_buttons(self.canal3buttons + [self.third_canal_check])
            else:
                self.activate_buttons(self.canal1buttons + [self.first_canal_check])
                self.activate_buttons(self.canal2buttons + [self.second_canal_check])
                self.activate_buttons(self.canal3buttons + [self.third_canal_check])
            if self.first_canal_check.isChecked():
                self.baseline_checkbox.setEnabled(False)
                self.activate_buttons(self.canal1buttons)
            else:
                self.deactivate_buttons(self.canal1buttons)
            if self.second_canal_check.isChecked():
                self.baseline_checkbox.setEnabled(False)
                self.activate_buttons(self.canal2buttons)
            else:
                self.deactivate_buttons(self.canal2buttons)
            if self.third_canal_check.isChecked():
                self.baseline_checkbox.setEnabled(False)
                self.activate_buttons(self.canal3buttons)
            else:
                self.deactivate_buttons(self.canal3buttons)
            if (
                self.first_canal_check.isChecked()
                or self.second_canal_check.isChecked()
                or self.third_canal_check.isChecked()
            ):
                self.deactivate_buttons([self.baseline_checkbox])
            else:
                self.activate_buttons([self.baseline_checkbox])
            self.tree.currentItem().setText(17, str(self.baseline_checkbox.isChecked()))
            self.tree.currentItem().setText(18, str(self.first_canal_check.isChecked()))
            self.tree.currentItem().setText(
                19, str(self.second_canal_check.isChecked())
            )
            self.tree.currentItem().setText(30, str(self.third_canal_check.isChecked()))
            self.enable_run(self.tree.check_global_validity())
            self.tree.graph(self.tree.currentItem(), current=True)
            self.draw()

    def enable_run(self, boolean):
        """Enable the run button"""
        if not self.daq_generated:
            boolean = False
        self.save_config_button.setEnabled(boolean)
        self.run_button.setEnabled(boolean)

    def disable_run(self):
        """Disable the run button"""
        self.save_config_button.setDisabled(True)
        self.run_button.setDisabled(True)

    def count_lights(self):
        """Return the number of lights and a list of their names"""
        count = 0
        text = []
        for checkbox in [
            self.ir_checkbox,
            self.red_checkbox,
            self.green_checkbox,
            self.fluorescence_checkbox,
        ]:
            if checkbox.isChecked():
                count += 1
                text.append(checkbox.text())
        return (count, text)

    def actualize_lights(self):
        """Update the lights list in the combo box"""
        self.preview_light_combo.clear()
        if self.count_lights()[0] == 0:
            self.preview_light_combo.setEnabled(False)
        else:
            self.preview_light_combo.setEnabled(True)
        for i in range(4):
            if i < self.count_lights()[0]:
                self.preview_light_combo.addItem(self.count_lights()[1][i])

    def boolean(self, string):
        """Return a boolean from a string"""
        if string == "True":
            return True
        return False

    def draw(self, root=False):
        """Draw the sitmulation channels graph
        
        Args:
            root (bool, optional): If True, the graph includes a progress bar"""
        try:
            self.plot_window.clear()
            self.plot_window.plot(
                self.tree.x_values, self.tree.stim1_values, root, index=0
            )
            self.plot_window.plot(
                self.tree.x_values,
                self.tree.stim2_values,
                root,
                index=1,
            )
            self.plot_window.plot(
                self.tree.x_values,
                self.tree.stim3_values,
                root,
                index=2,
            )
            self.tree.x_values = []
            self.tree.stim1_values = []
            self.tree.stim2_values = []
            self.tree.stim3_values = []
            self.elapsed_time = 0
        except Exception as err:
            pass

    def set_roi(self):
        """Set the ROI"""
        self.deactivate_buttons(buttons=self.enabled_buttons)
        self.stop_button.setEnabled(False)
        self.save_roi_button.setEnabled(False)
        self.roi_buttons.setCurrentIndex(1)

        def onselect_function(eclick, erelease):
            """Save the ROI dimensions as attributes"""
            self.roi_extent = self.rect_selector.extents
            self.save_roi_button.setEnabled(True)

        self.rect_selector = RectangleSelector(
            self.plot_image.axes,
            onselect_function,
            drawtype="box",
            useblit=True,
            button=[1, 3],
            minspanx=5,
            minspany=5,
            spancoords="pixels",
            interactive=True,
        )

    def reset_roi(self):
        """Reset the ROI"""
        plt.figure(self.image_view.figure.number)
        plt.xlim(0, int(1024 / self.config["Binning"]))
        plt.ylim(0, int(1024 / self.config["Binning"]))
        self.roi_extent = None
        self.reset_roi_button.setEnabled(False)

    def cancel_roi(self):
        """Cancel the ROI selection"""
        self.activate_buttons(buttons=self.enabled_buttons)
        self.roi_buttons.setCurrentIndex(0)
        self.rect_selector.clear()
        self.rect_selector = None

    def save_roi(self):
        """Save the ROI"""
        self.activate_buttons(buttons=self.enabled_buttons)
        self.roi_buttons.setCurrentIndex(0)
        plt.figure(self.image_view.figure.number)
        plt.ion()
        print(self.roi_extent)
        plt.xlim(self.roi_extent[0], self.roi_extent[1])
        plt.ylim(self.roi_extent[2], self.roi_extent[3])
        self.rect_selector.clear()
        self.rect_selector = None
        self.reset_roi_button.setEnabled(True)

    def verify_exposure(self):
        """Verify if the exposure/framerate combination is valid"""
        try:
            boolean_check = (int(self.exposure_cell.text()) / 1000 + 0.0015) * int(
                self.framerate_cell.text()
            ) < 1 and int(self.framerate_cell.text()) <= 57
        except Exception:
            boolean_check = False
        self.exposure_warning_label.setHidden(boolean_check)

    def check_if_thread_is_alive(self):
        """Check what threads are alive"""
        try:
            if self.live_preview_thread.is_alive():
                print("Live preview thread is alive")
            else:
                print("Live preview thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.start_experiment_thread.is_alive():
                print("Start Experiment thread is alive")
            else:
                print("Start experiment thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.daq_generation_thread.is_alive():
                print("Daq Generation thread is alive")
            else:
                print("Daq generation thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.signal_preview_thread.is_alive():
                print("Signal Preview thread is alive")
            else:
                print("Signal Preview thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.live_save_thread.is_alive():
                print("Live Save thread is alive")
            else:
                print("Live Save thread is dead")
        except Exception as err:
            print(err)

        try:
            if self.baseline_check_thread.is_alive():
                print("Baseline check thread is alive")
            else:
                print("Baseline check thread is dead")
        except Exception as err:
            print(err)

    def initialize_buttons(self):
        """Define list of buttons to activate/deactivate"""
        self.canal1buttons = [
            self.stim_type_cell,
            self.pulses_label,
            self.pulses_cell,
            self.width_label,
            self.width_cell,
            self.jitter_label,
            self.jitter_cell,
            self.frequency_label,
            self.frequency_cell,
            self.duty_label,
            self.duty_cell,
            self.heigth_cell,
            self.heigth_label,
        ]
        self.canal2buttons = [
            self.stim_type_cell2,
            self.pulses_label2,
            self.pulses_cell2,
            self.width_label2,
            self.width_cell2,
            self.jitter_label2,
            self.jitter_cell2,
            self.frequency_label2,
            self.frequency_cell2,
            self.duty_label2,
            self.duty_cell2,
            self.heigth_cell2,
            self.heigth_label2,
        ]
        self.canal3buttons = [
            self.stim_type_cell3,
            self.pulses_label3,
            self.pulses_cell3,
            self.width_label3,
            self.width_cell3,
            self.jitter_label3,
            self.jitter_cell3,
            self.frequency_label3,
            self.frequency_cell3,
            self.duty_label3,
            self.duty_cell3,
            self.heigth_cell3,
            self.heigth_label3,
        ]
        self.enabled_buttons = [
            self.run_button,
            self.experiment_name_cell,
            self.mouse_id_cell,
            self.directory_choose_button,
            self.set_roi_button,
            self.reset_roi_button,
            self.experiment_name,
            self.mouse_id_label,
            self.framerate_label,
            self.framerate_cell,
            self.exposure_cell,
            self.exposure_label,
            self.add_brother_branch_button,
            self.add_child_branch_button,
            self.delete_item_button,
            self.red_checkbox,
            self.ir_checkbox,
            self.green_checkbox,
            self.fluorescence_checkbox,
            self.stimulation_name_label,
            self.directory_save_files_checkbox,
            self.stimulation_name_cell,
            self.stim_type_cell,
            self.stim_type_cell2,
            self.first_canal_check,
            self.second_canal_check,
            self.first_signal_type_duration_label,
            self.duration_cell,
            self.pulses_label,
            self.pulses_cell,
            self.width_label,
            self.width_cell,
            self.jitter_label,
            self.jitter_cell,
            self.frequency_label,
            self.frequency_cell,
            self.heigth_label,
            self.heigth_cell,
            self.duty_label,
            self.duty_cell,
            self.pulses_label2,
            self.pulses_cell2,
            self.width_label2,
            self.width_cell2,
            self.jitter_label2,
            self.jitter_cell2,
            self.frequency_label2,
            self.frequency_cell2,
            self.heigth_label2,
            self.heigth_cell2,
            self.duty_label2,
            self.duty_cell2,
            self.third_canal_check,
            self.stim_type_cell3,
            self.pulses_label3,
            self.pulses_cell3,
            self.width_label3,
            self.width_cell3,
            self.jitter_label3,
            self.jitter_cell3,
            self.frequency_label3,
            self.frequency_cell3,
            self.duty_label3,
            self.duty_cell3,
            self.heigth_cell3,
            self.heigth_label3,
            self.block_iterations_label,
            self.block_iterations_cell,
            self.block_delay_label,
            self.block_delay_cell,
            self.block_jitter_label,
            self.block_jitter_cell,
            self.block_name_label,
            self.block_name_cell,
            self.activate_live_preview_button,
            self.deactivate_live_preview_button,
            self.tree,
        ]

Ancestors

  • PyQt5.QtWidgets.QWidget
  • PyQt5.QtCore.QObject
  • sip.wrapper
  • PyQt5.QtGui.QPaintDevice
  • sip.simplewrapper

Methods

def activate_buttons(self, buttons)

Activate the buttons in a list

Expand source code
def activate_buttons(self, buttons):
    """Activate the buttons in a list"""
    for button in buttons:
        button.setEnabled(True)
    if buttons == self.enabled_buttons:
        if self.directory_save_files_checkbox.isChecked():
            self.directory_choose_button.setEnabled(True)
        if self.roi_extent is None:
            self.reset_roi_button.setEnabled(False)
        else:
            self.set_roi_button.setEnabled(False)
        self.stop_button.setDisabled(True)
def actualize_daq(self)

Actualize the DAQ with the current settings

Expand source code
def actualize_daq(self):
    """Actualize the DAQ with the current settings"""
    try:
        self.daq.lights = []
        if self.ir_checkbox.isChecked():
            self.daq.lights.append(Instrument(self.ports["infrared"], "ir"))
        if self.red_checkbox.isChecked():
            self.daq.lights.append(Instrument(self.ports["red"], "red"))
        if self.green_checkbox.isChecked():
            self.daq.lights.append(Instrument(self.ports["green"], "green"))
        if self.fluorescence_checkbox.isChecked():
            self.daq.lights.append(Instrument(self.ports["blue"], "blue"))
        self.daq.framerate = int(self.framerate_cell.text())
        self.daq.exposure = int(self.exposure_cell.text()) / 1000
        self.camera.frames = []
        self.daq.stop_signal = False
    except Exception:
        pass
def actualize_lights(self)

Update the lights list in the combo box

Expand source code
def actualize_lights(self):
    """Update the lights list in the combo box"""
    self.preview_light_combo.clear()
    if self.count_lights()[0] == 0:
        self.preview_light_combo.setEnabled(False)
    else:
        self.preview_light_combo.setEnabled(True)
    for i in range(4):
        if i < self.count_lights()[0]:
            self.preview_light_combo.addItem(self.count_lights()[1][i])
def actualize_progression(self)

Actualize the position of the progress bar

Expand source code
def actualize_progression(self):
    """Actualize the position of the progress bar"""
    plt.ion()
    while self.daq.stop_signal is False:
        try:
            if self.acquisition_mode:
                position = self.camera.frames_read / int(self.framerate_cell.text())
            else:
                position = time.time() - self.daq.start_time
            self.plot_window.vertical_lines[0].set_xdata(position)
            self.plot_window.vertical_lines[1].set_xdata(position)
            self.plot_window.vertical_lines[2].set_xdata(position)
            time.sleep(0.5)
        except Exception as err:
            time.sleep(0.5)
            pass
def actualize_window(self)

Actualize the 'Stimulation Edit' and 'Signal Preview' windows

Expand source code
def actualize_window(self):
    """Actualize the 'Stimulation Edit' and 'Signal Preview' windows"""
    self.activate_buttons(
        [self.add_child_branch_button, self.add_brother_branch_button]
    )
    if self.tree.currentItem():
        self.tree_switch_window.setCurrentIndex(0)
    else:
        self.tree_switch_window.setCurrentIndex(1)
    try:
        if self.tree.currentItem().childCount() > 0:
            self.signal_adjust_superposed.setCurrentIndex(1)
        else:
            self.signal_adjust_superposed.setCurrentIndex(0)
    except AttributeError:
        self.signal_adjust_superposed.setCurrentIndex(2)
    self.tree_to_name()
    self.tree_to_block()
    self.tree_to_type()
    self.tree_to_signal()
    self.tree_to_canal()
    self.tree.graph(self.tree.currentItem(), current=True)
    self.draw()
def adjust_exposure(self)

Match the exposure of the image preview to the slider value

Expand source code
def adjust_exposure(self):
    """Match the exposure of the image preview to the slider value"""
    self.max_exposure = self.exposure_slider.value()
    self.slider_values[self.preview_light_combo.currentText()][
        self.activation_map_combo.currentText()
    ] = self.max_exposure
def adjust_slider(self)

Adjust the saturation slider using corresponding value in dictionary

Expand source code
def adjust_slider(self):
    """Adjust the saturation slider using corresponding value in dictionary"""
    try:
        value = self.slider_values[self.preview_light_combo.currentText()][
            self.activation_map_combo.currentText()
        ]
        self.exposure_slider.setValue(value)
    except Exception:
        pass
def block_to_tree(self)

Transfer the block attributes from the cells to the tree

Expand source code
def block_to_tree(self):
    """Transfer the block attributes from the cells to the tree"""
    self.tree.currentItem().setText(1, self.block_iterations_cell.text())
    self.tree.currentItem().setText(2, self.block_delay_cell.text())
    self.tree.currentItem().setText(3, self.block_jitter_cell.text())
    self.enable_run(self.tree.check_global_validity())
    self.tree.graph(self.tree.currentItem(), current=True)
    self.draw()
def boolean(self, string)

Return a boolean from a string

Expand source code
def boolean(self, string):
    """Return a boolean from a string"""
    if string == "True":
        return True
    return False
def canals_to_tree(self)

Transfer the canals attributes from the cells to the tree

Expand source code
def canals_to_tree(self):
    """Transfer the canals attributes from the cells to the tree"""
    self.baseline_checkbox.setEnabled(True)
    if not self.canal_running:
        if self.baseline_checkbox.isChecked():
            self.deactivate_buttons(self.canal1buttons + [self.first_canal_check])
            self.deactivate_buttons(self.canal2buttons + [self.second_canal_check])
            self.deactivate_buttons(self.canal3buttons + [self.third_canal_check])
        else:
            self.activate_buttons(self.canal1buttons + [self.first_canal_check])
            self.activate_buttons(self.canal2buttons + [self.second_canal_check])
            self.activate_buttons(self.canal3buttons + [self.third_canal_check])
        if self.first_canal_check.isChecked():
            self.baseline_checkbox.setEnabled(False)
            self.activate_buttons(self.canal1buttons)
        else:
            self.deactivate_buttons(self.canal1buttons)
        if self.second_canal_check.isChecked():
            self.baseline_checkbox.setEnabled(False)
            self.activate_buttons(self.canal2buttons)
        else:
            self.deactivate_buttons(self.canal2buttons)
        if self.third_canal_check.isChecked():
            self.baseline_checkbox.setEnabled(False)
            self.activate_buttons(self.canal3buttons)
        else:
            self.deactivate_buttons(self.canal3buttons)
        if (
            self.first_canal_check.isChecked()
            or self.second_canal_check.isChecked()
            or self.third_canal_check.isChecked()
        ):
            self.deactivate_buttons([self.baseline_checkbox])
        else:
            self.activate_buttons([self.baseline_checkbox])
        self.tree.currentItem().setText(17, str(self.baseline_checkbox.isChecked()))
        self.tree.currentItem().setText(18, str(self.first_canal_check.isChecked()))
        self.tree.currentItem().setText(
            19, str(self.second_canal_check.isChecked())
        )
        self.tree.currentItem().setText(30, str(self.third_canal_check.isChecked()))
        self.enable_run(self.tree.check_global_validity())
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()
def cancel_roi(self)

Cancel the ROI selection

Expand source code
def cancel_roi(self):
    """Cancel the ROI selection"""
    self.activate_buttons(buttons=self.enabled_buttons)
    self.roi_buttons.setCurrentIndex(0)
    self.rect_selector.clear()
    self.rect_selector = None
def change_preview_light_channel(self)

Change the light channel for the live preview

Expand source code
def change_preview_light_channel(self):
    """Change the light channel for the live preview"""
    self.live_preview_light_index = self.preview_light_combo.currentIndex()
    self.adjust_slider()
def check_baseline(self)

Monitor the incoming frames and check if the baseline is reached

Expand source code
def check_baseline(self):
    """Monitor the incoming frames and check if the baseline is reached"""
    if len(self.daq.lights) > 0:
        self.camera.baseline_data = []
        self.camera.adding_frames = False
        self.camera.completed_baseline = False
        while self.daq.camera_signal is None:
            pass
        frames_acquired = frames_acquired_from_camera_signal(self.daq.camera_signal)
        baseline_indices = get_baseline_frame_indices(
            self.tree.baseline_values, frames_acquired
        )
        for baseline_pair in baseline_indices:
            while not self.daq.stop_signal:
                try:
                    if (
                        not self.camera.adding_frames
                        and self.camera.frames_read >= baseline_pair[0]
                    ):
                        self.camera.adding_frames = True
                    elif (
                        self.camera.adding_frames
                        and self.camera.frames_read >= baseline_pair[1]
                    ):
                        self.camera.baseline_read_list = []
                        self.camera.average_baseline = average_baseline(
                            self.camera.baseline_data,
                            len(self.daq.lights),
                            self.camera.frames_read_list[0] % len(self.daq.lights),
                        )
                        self.camera.adding_frames = False
                        self.camera.baseline_frames = []
                        self.camera.baseline_completed = True
                        self.camera.frames_read_list = []
                        break
                except Exception as err:
                    pass
                time.sleep(0.01)
def check_if_thread_is_alive(self)

Check what threads are alive

Expand source code
def check_if_thread_is_alive(self):
    """Check what threads are alive"""
    try:
        if self.live_preview_thread.is_alive():
            print("Live preview thread is alive")
        else:
            print("Live preview thread is dead")
    except Exception as err:
        print(err)

    try:
        if self.start_experiment_thread.is_alive():
            print("Start Experiment thread is alive")
        else:
            print("Start experiment thread is dead")
    except Exception as err:
        print(err)

    try:
        if self.daq_generation_thread.is_alive():
            print("Daq Generation thread is alive")
        else:
            print("Daq generation thread is dead")
    except Exception as err:
        print(err)

    try:
        if self.signal_preview_thread.is_alive():
            print("Signal Preview thread is alive")
        else:
            print("Signal Preview thread is dead")
    except Exception as err:
        print(err)

    try:
        if self.live_save_thread.is_alive():
            print("Live Save thread is alive")
        else:
            print("Live Save thread is dead")
    except Exception as err:
        print(err)

    try:
        if self.baseline_check_thread.is_alive():
            print("Baseline check thread is alive")
        else:
            print("Baseline check thread is dead")
    except Exception as err:
        print(err)
def check_override(self)

Check if experiment with the same name already exists

Expand source code
def check_override(self):
    """Check if experiment with the same name already exists"""
    if os.path.isfile(
        os.path.join(
            self.directory_cell.text(),
            self.experiment_name_cell.text(),
            f"{self.experiment_name_cell.text()}-light_signal.npy",
        )
    ):
        button = QMessageBox.question(
            self,
            "Files already exist",
            "Files already exist. \n Do you want to override the existing files?",
        )
        if button == QMessageBox.Yes:
            return True
        else:
            return False
    else:
        return True
def choose_directory(self)

Choose the directory where to save the files

Expand source code
def choose_directory(self):
    """Choose the directory where to save the files"""
    folder = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
    self.directory_cell.setText(folder)
def closeEvent(self, *args, **kwargs)

Stop all processes when closing the application

Expand source code
def closeEvent(self, *args, **kwargs):
    """Stop all processes when closing the application"""
    self.video_running = False
    try:
        self.camera.stop_signal = True
        self.camera.video_running = False
        self.daq.stop_signal = True
        self.daq.camera.cam.stop_acquisition()
        print("Program Closed")
    except Exception as err:
        pass
    self.check_if_thread_is_alive()
def count_lights(self)

Return the number of lights and a list of their names

Expand source code
def count_lights(self):
    """Return the number of lights and a list of their names"""
    count = 0
    text = []
    for checkbox in [
        self.ir_checkbox,
        self.red_checkbox,
        self.green_checkbox,
        self.fluorescence_checkbox,
    ]:
        if checkbox.isChecked():
            count += 1
            text.append(checkbox.text())
    return (count, text)
def deactivate_buttons(self, buttons)

Deactivate the buttons in a list

Expand source code
def deactivate_buttons(self, buttons):
    """Deactivate the buttons in a list"""
    if buttons == self.enabled_buttons:
        self.stop_button.setEnabled(True)
        self.tree.clearSelection()
    for button in buttons:
        button.setDisabled(True)
def deactivate_channels(self)

Deactivate canal checkboxes if the baseline checkbox is checked

Expand source code
def deactivate_channels(self):
    """Deactivate canal checkboxes if the baseline checkbox is checked"""
    if self.baseline_checkbox.isChecked():
        self.deactivate_buttons(
            [
                self.first_canal_check,
                self.second_canal_check,
            ]
        )
    else:
        self.activate_buttons(
            [
                self.first_canal_check,
                self.second_canal_check,
            ]
        )
def disable_run(self)

Disable the run button

Expand source code
def disable_run(self):
    """Disable the run button"""
    self.save_config_button.setDisabled(True)
    self.run_button.setDisabled(True)
def draw(self, root=False)

Draw the sitmulation channels graph

Args

root : bool, optional
If True, the graph includes a progress bar
Expand source code
def draw(self, root=False):
    """Draw the sitmulation channels graph
    
    Args:
        root (bool, optional): If True, the graph includes a progress bar"""
    try:
        self.plot_window.clear()
        self.plot_window.plot(
            self.tree.x_values, self.tree.stim1_values, root, index=0
        )
        self.plot_window.plot(
            self.tree.x_values,
            self.tree.stim2_values,
            root,
            index=1,
        )
        self.plot_window.plot(
            self.tree.x_values,
            self.tree.stim3_values,
            root,
            index=2,
        )
        self.tree.x_values = []
        self.tree.stim1_values = []
        self.tree.stim2_values = []
        self.tree.stim3_values = []
        self.elapsed_time = 0
    except Exception as err:
        pass
def enable_directory(self)

Enable the directory cell

Expand source code
def enable_directory(self):
    """Enable the directory cell"""
    self.files_saved = self.directory_save_files_checkbox.isChecked()
    self.directory_choose_button.setEnabled(self.files_saved)
    self.directory_cell.setEnabled(self.files_saved)
def enable_run(self, boolean)

Enable the run button

Expand source code
def enable_run(self, boolean):
    """Enable the run button"""
    if not self.daq_generated:
        boolean = False
    self.save_config_button.setEnabled(boolean)
    self.run_button.setEnabled(boolean)
def generate_daq(self)

Generate the DAQ

Expand source code
def generate_daq(self):
    """Generate the DAQ"""
    try:
        self.camera = Camera(self.ports["camera"], "name")
    except Exception:
        self.camera = None
    self.stimuli = [
        Instrument(self.ports["analog0"], "air-pump"),
        Instrument(self.ports["analog1"], "air-pump2"),
        Instrument(self.ports["co2"], "air-pump3"),
    ]
    self.daq = DAQ(
        "dev1",
        [],
        self.stimuli,
        self.camera,
        int(self.framerate_cell.text()),
        int(self.exposure_cell.text()) / 1000,
    )
    self.daq.close_all_lights(self.ports)
    self.daq_generated = True
    self.enable_run(self.tree.check_global_validity())
def handler(*args, **kwargs)

Ignore Qt messages

Expand source code
def handler(*args, **kwargs):
    """Ignore Qt messages"""
    pass
def hide_buttons(self, buttons)

Hide the buttons in a list

Expand source code
def hide_buttons(self, buttons):
    """Hide the buttons in a list"""
    for button in buttons:
        button.setVisible(False)
def import_config(self)

Import a configuration file

Expand source code
def import_config(self):
    """Import a configuration file"""
    file = QFileDialog.getOpenFileName()[0]
    try:
        dictionary = get_dictionary(file)
        self.framerate_cell.setText(str(dictionary["Framerate"]))
        self.exposure_cell.setText(str(dictionary["Exposition"]))
        self.set_lights(dictionary["Lights"])
        self.tree.create_tree_item(dictionary["Blocks"])
        self.enable_run(self.tree.check_global_validity())
        self.tree.graph(self.tree.invisibleRootItem())
        self.draw()
    except Exception as err:
        print(err)
def initUI(self)

Initialize the user interface

Expand source code
def initUI(self):
    """Initialize the user interface"""
    self.title = "Widefield Imaging Aquisition"
    self.dimensions = (10, 10, 640, 480)
    self.setWindowTitle(self.title)
    self.setGeometry(*self.dimensions)

    # self.grid_layout = QGridLayout()
    # self.setLayout(self.grid_layout)
    self.grid_layout.setAlignment(Qt.AlignTop)

    self.experiment_settings_label = QLabel("Experiment Settings")
    self.experiment_settings_label.setFont(QFont("IBM Plex Sans", 17))
    self.grid_layout.addWidget(self.experiment_settings_label, 0, 0)

    self.experiment_settings_main_window = QVBoxLayout()
    self.experiment_name_window = QHBoxLayout()
    self.experiment_name = QLabel("Experiment Name")
    self.experiment_name_window.addWidget(self.experiment_name)
    self.experiment_name_cell = QLineEdit()
    self.experiment_name_window.addWidget(self.experiment_name_cell)
    self.experiment_settings_main_window.addLayout(self.experiment_name_window)

    self.mouse_id_window = QHBoxLayout()
    self.mouse_id_label = QLabel("Mouse ID")
    self.mouse_id_window.addWidget(self.mouse_id_label)
    self.mouse_id_cell = QLineEdit()
    self.mouse_id_window.addWidget(self.mouse_id_cell)
    self.experiment_settings_main_window.addLayout(self.mouse_id_window)

    self.framerate_exposure_window = QHBoxLayout()
    self.exposure_window = QHBoxLayout()
    self.exposure_label = QLabel("Exposure (ms)")
    self.exposure_window.addWidget(self.exposure_label)
    self.exposure_cell = QLineEdit("10")
    self.exposure_cell.setValidator(self.onlyExposure)
    self.exposure_cell.textChanged.connect(self.verify_exposure)
    self.exposure_window.addWidget(self.exposure_cell)
    self.framerate_exposure_window.addLayout(self.exposure_window)
    self.framerate_window = QHBoxLayout()
    self.framerate_label = QLabel("Framerate")
    self.framerate_window.addWidget(self.framerate_label)
    self.framerate_cell = QLineEdit("30")
    self.framerate_cell.setValidator(self.onlyFramerate)
    self.framerate_cell.textChanged.connect(self.verify_exposure)
    self.framerate_window.addWidget(self.framerate_cell)
    self.framerate_exposure_window.addLayout(self.framerate_window)

    if self.acquisition_mode:
        self.experiment_settings_main_window.addLayout(
            self.framerate_exposure_window
        )

    self.exposure_warning_label = QLabel("Invalid Exposure / Frame Rate")
    if self.acquisition_mode:
        self.experiment_settings_main_window.addWidget(self.exposure_warning_label)
    self.exposure_warning_label.setStyleSheet("color: red")
    self.exposure_warning_label.setHidden(True)

    self.directory_window = QHBoxLayout()
    self.directory_save_files_checkbox = QCheckBox()
    self.directory_save_files_checkbox.setText("Save")
    self.directory_save_files_checkbox.stateChanged.connect(self.enable_directory)
    self.directory_window.addWidget(self.directory_save_files_checkbox)
    self.directory_choose_button = QPushButton("Select Directory")
    self.directory_choose_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "folder-plus.png"))
    )
    # self.directory_choose_button.setIcon(QIcon(os.path.join("gui", "icons", "folder-plus.png")))
    self.directory_choose_button.setDisabled(True)
    self.directory_choose_button.clicked.connect(self.choose_directory)
    self.directory_window.addWidget(self.directory_choose_button)
    self.directory_cell = QLineEdit("")
    self.directory_cell.setReadOnly(True)
    self.directory_window.addWidget(self.directory_cell)
    self.experiment_settings_main_window.addLayout(self.directory_window)
    self.trigger_checkbox = QCheckBox("Wait for Trigger")
    self.trigger_activated = False
    self.trigger_checkbox.stateChanged.connect(self.set_trigger)
    # self.experiment_settings_main_window.addWidget(self.trigger_checkbox)

    self.save_config_button = QPushButton("Save Config")
    self.save_config_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "save.png"))
    )
    self.save_config_button.clicked.connect(self.save_config)
    self.save_config_button.setEnabled(False)
    self.experiment_settings_main_window.addWidget(self.save_config_button)

    self.experiment_settings_main_window.addStretch()

    if self.acquisition_mode:
        self.grid_layout.addLayout(self.experiment_settings_main_window, 1, 0)
    else:
        self.grid_layout.addLayout(self.experiment_settings_main_window, 1, 0, 1, 2)

    self.image_settings_label = QLabel("Image Settings")
    self.image_settings_label.setFont(QFont("IBM Plex Sans", 17))
    if self.acquisition_mode:
        self.grid_layout.addWidget(self.image_settings_label, 0, 1)

    self.image_settings_main_window = QVBoxLayout()
    self.image_settings_main_window.setAlignment(Qt.AlignLeft)
    self.image_settings_main_window.setAlignment(Qt.AlignTop)

    self.image_settings_second_window = QHBoxLayout()
    self.ir_checkbox = QCheckBox("Infrared")
    self.ir_checkbox.stateChanged.connect(self.actualize_lights)
    self.image_settings_second_window.addWidget(self.ir_checkbox)
    self.red_checkbox = QCheckBox("Red")
    self.red_checkbox.stateChanged.connect(self.actualize_lights)
    self.image_settings_second_window.addWidget(self.red_checkbox)
    self.green_checkbox = QCheckBox("Green")
    self.green_checkbox.stateChanged.connect(self.actualize_lights)
    self.image_settings_second_window.addWidget(self.green_checkbox)
    self.fluorescence_checkbox = QCheckBox("Blue")
    self.fluorescence_checkbox.stateChanged.connect(self.actualize_lights)
    self.image_settings_second_window.addWidget(self.fluorescence_checkbox)

    self.light_channel_layout = QHBoxLayout()
    self.preview_light_label = QLabel("Light Channel Preview")
    self.light_channel_layout.addWidget(self.preview_light_label)
    self.preview_light_combo = QComboBox()
    self.preview_light_combo.setEnabled(False)
    self.preview_light_combo.currentIndexChanged.connect(
        self.change_preview_light_channel
    )
    self.light_channel_layout.addWidget(self.preview_light_combo)
    # self.activation_map_checkbox = QCheckBox("Show Activation Map")
    self.activation_map_window = QHBoxLayout()
    self.activation_map_label = QLabel("Activation Map")
    self.activation_map_window.addWidget(self.activation_map_label)
    self.activation_map_combo = QComboBox()
    self.activation_map_combo.addItem("None")
    self.activation_map_combo.addItem("Normal")
    self.activation_map_combo.addItem("Logarithmic")
    self.activation_map_combo.currentIndexChanged.connect(self.adjust_slider)
    self.activation_map_window.addWidget(self.activation_map_combo)

    self.image_settings_main_window.addLayout(self.image_settings_second_window)
    self.image_settings_main_window.addLayout(self.light_channel_layout)
    # self.image_settings_main_window.addWidget(self.activation_map_checkbox)
    self.image_settings_main_window.addLayout(self.activation_map_window)

    self.roi_buttons = QStackedLayout()

    self.roi_layout1 = QHBoxLayout()
    self.roi_layout1.setAlignment(Qt.AlignLeft)
    self.roi_layout1.setAlignment(Qt.AlignTop)
    self.roi_layout1.setContentsMargins(0, 0, 0, 0)
    self.reset_roi_button = QPushButton()
    self.reset_roi_button.setText("Reset ROI")
    self.reset_roi_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-out-area.png"))
    )
    # self.reset_roi_button.setIcon(QIcon("gui/icons/zoom-out-area.png"))
    self.reset_roi_button.setEnabled(False)
    self.reset_roi_button.clicked.connect(self.reset_roi)
    self.roi_layout1.addWidget(self.reset_roi_button)

    self.set_roi_button = QPushButton()
    self.set_roi_button.setText("Set ROI")
    self.set_roi_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-in-area.png"))
    )
    self.set_roi_button.clicked.connect(self.set_roi)
    self.roi_layout1.addWidget(self.set_roi_button)
    self.roi_layout1_container = QWidget()
    self.roi_layout1_container.setLayout(self.roi_layout1)

    self.roi_layout2 = QHBoxLayout()
    self.roi_layout2.setAlignment(Qt.AlignLeft)
    self.roi_layout2.setAlignment(Qt.AlignTop)
    self.roi_layout2.setContentsMargins(0, 0, 0, 0)
    self.cancel_roi_button = QPushButton()
    self.cancel_roi_button.setText("Cancel")
    self.cancel_roi_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-cancel.png"))
    )
    self.cancel_roi_button.clicked.connect(self.cancel_roi)
    self.roi_layout2.addWidget(self.cancel_roi_button)

    self.save_roi_button = QPushButton()
    self.save_roi_button.setText("Save ROI")
    self.save_roi_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "zoom-check.png"))
    )
    self.save_roi_button.clicked.connect(self.save_roi)
    self.roi_layout2.addWidget(self.save_roi_button)
    self.roi_layout2_container = QWidget()
    self.roi_layout2_container.setLayout(self.roi_layout2)

    if self.acquisition_mode:
        self.roi_buttons.addWidget(self.roi_layout1_container)
        self.roi_buttons.addWidget(self.roi_layout2_container)
        self.image_settings_main_window.addLayout(self.roi_buttons)

    self.exposure_slider = QSlider(Qt.Horizontal, self)
    self.exposure_slider.setRange(0, 4096)
    self.exposure_slider.setValue(4096)
    self.exposure_slider.valueChanged.connect(self.adjust_exposure)
    self.image_settings_main_window.addWidget(self.exposure_slider)
    self.image_settings_main_window.addStretch()

    self.activate_live_preview_button = QPushButton()
    self.activate_live_preview_button.setText("Start Live Preview")
    self.activate_live_preview_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "video.png"))
    )
    self.activate_live_preview_button.clicked.connect(self.open_live_preview_thread)

    self.deactivate_live_preview_button = QPushButton()
    self.deactivate_live_preview_button.setText("Stop Live Preview")
    self.deactivate_live_preview_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "video-off.png"))
    )
    self.deactivate_live_preview_button.clicked.connect(self.stop_live)

    self.image_settings_main_window.addStretch()

    if self.acquisition_mode:
        self.grid_layout.addLayout(self.image_settings_main_window, 1, 1)

    self.live_preview_label = QLabel("Live Preview")
    self.live_preview_label.setFont(QFont("IBM Plex Sans", 17))
    self.image_view = PlotWindow()
    self.plot_image = plt.imshow(
        np.zeros(
            (int(1024 / self.config["Binning"]), int(1024 / self.config["Binning"]))
        ),
        cmap="binary_r",
        vmin=0,
        vmax=4096,
        origin="lower",
    )
    self.plot_image.axes.get_xaxis().set_visible(False)
    self.plot_image.axes.axes.get_yaxis().set_visible(False)

    if self.acquisition_mode:
        self.grid_layout.addWidget(self.live_preview_label, 0, 2)
        self.grid_layout.addWidget(self.image_view, 1, 2)

    self.tree_label = QLabel("Stimulation Tree")
    self.tree_label.setFont(QFont("IBM Plex Sans", 17))
    self.grid_layout.addWidget(self.tree_label, 2, 0)

    self.tree_window = QVBoxLayout()
    self.tree = Tree()
    self.tree.setHeaderLabels(
        [
            "0 Name",
            "1 Iterations",
            "2 Delay",
            "3 Jitter",
            "4 Type",
            "5 Pulses",
            "6 Duration",
            "7 Jitter",
            "8 Width",
            "9 Frequency",
            "10 Duty",
            "11 Type2",
            "12 Pulses 2",
            "13 Jitter 2",
            "14 Width 2",
            "15 Frequency 2",
            "16 Duty 2",
            "17 Baseline",
            "18 Canal 1",
            "19 Canal 2",
            "20 Valid",
            "21 Heigth",
            "22 Heigth 2",
            "23 Type 3",
            "24 Pulses 3",
            "25 Jitter 3",
            "26 Width 3",
            "27 Frequency 3",
            "28 Duty 3",
            "29 Heigth 3",
            "30 Canal 3",
        ]
    )
    if not self.config["Debug"]:
        for i in range(1, 20):
            self.tree.header().hideSection(i)
        for i in range(21, 31):
            self.tree.header().hideSection(i)
        self.tree.setHeaderHidden(True)
        self.tree.header().setSectionResizeMode(0, QHeaderView.Stretch)
        self.tree.header().setStretchLastSection(False)
    self.tree.currentItemChanged.connect(self.actualize_window)
    self.tree_window.addWidget(self.tree)

    self.tree_switch_window = QStackedLayout()
    self.tree_second_window = QHBoxLayout()
    self.stim_buttons_container = QWidget()
    self.delete_item_button = QPushButton("Delete")
    self.delete_item_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "trash.png"))
    )
    self.delete_item_button.clicked.connect(self.tree.delete_item)
    self.tree_second_window.addWidget(self.delete_item_button)
    self.add_brother_branch_button = QPushButton("Add Sibling")
    self.add_brother_branch_button.clicked.connect(self.tree.add_brother)
    self.add_brother_branch_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "arrow-bar-down.png"))
    )
    self.tree_second_window.addWidget(self.add_brother_branch_button)
    self.add_child_branch_button = QPushButton("Add Child")
    self.add_child_branch_button.clicked.connect(self.tree.add_child)
    self.add_child_branch_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "arrow-bar-right.png"))
    )
    self.tree_second_window.addWidget(self.add_child_branch_button)
    self.stim_buttons_container.setLayout(self.tree_second_window)
    self.tree_switch_window.addWidget(self.stim_buttons_container)

    self.tree_third_window = QHBoxLayout()
    self.import_button = QPushButton("Import Configuration")
    self.import_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "packge-import.png"))
    )
    self.import_button.clicked.connect(self.import_config)
    self.tree_third_window.addWidget(self.import_button)
    self.new_branch_button = QPushButton("New Stimulation")
    self.new_branch_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "square-plus.png"))
    )
    self.tree_third_window.addWidget(self.new_branch_button)
    self.stim_buttons_container2 = QWidget()
    self.stim_buttons_container2.setLayout(self.tree_third_window)
    self.tree_switch_window.addWidget(self.stim_buttons_container2)
    self.new_branch_button.clicked.connect(self.tree.first_stimulation)
    self.grid_layout.addLayout(self.tree_switch_window, 4, 0)

    self.tree_switch_window.setCurrentIndex(1)
    self.grid_layout.addLayout(self.tree_window, 3, 0)

    self.signal_adjust_label = QLabel("Signal Adjust")
    self.signal_adjust_label.setFont(QFont("IBM Plex Sans", 17))
    self.grid_layout.addWidget(self.signal_adjust_label, 2, 1)

    self.signal_adjust_superposed = QStackedLayout()
    self.stimulation_edit_layout = QVBoxLayout()
    self.stimulation_edit_layout.setContentsMargins(0, 0, 0, 0)

    self.canal_window = QVBoxLayout()
    self.canal_window.setAlignment(Qt.AlignLeft)
    self.canal_window.setAlignment(Qt.AlignTop)
    self.canal_window.setContentsMargins(0, 0, 0, 0)

    self.first_canal_check = QCheckBox()
    self.first_canal_check.stateChanged.connect(self.canals_to_tree)
    self.first_canal_check.setText("Canal 1")

    self.stim_type_cell = QComboBox()
    self.stim_type_cell.addItem("square")
    self.stim_type_cell.addItem("random-square")
    self.stim_type_cell.addItem("Third")
    self.stim_type_cell.currentIndexChanged.connect(self.type_to_tree)
    self.stimulation_type_window = QHBoxLayout()
    self.stimulation_type_window.addWidget(self.first_canal_check)
    self.stimulation_type_window.addWidget(self.stim_type_cell)
    self.canal_window.addLayout(self.stimulation_type_window)

    self.different_signals_window = QStackedLayout()
    self.canal_window.addLayout(self.different_signals_window)

    self.second_canal_check = QCheckBox()
    self.second_canal_check.stateChanged.connect(self.canals_to_tree)
    self.second_canal_check.setText("Canal 2")

    self.stim_type_cell2 = QComboBox()
    self.stim_type_cell2.addItem("square")
    self.stim_type_cell2.addItem("random-square")
    self.stim_type_cell2.addItem("Third")
    self.stim_type_cell2.currentIndexChanged.connect(self.type_to_tree)
    self.stimulation_type_window2 = QHBoxLayout()
    self.stimulation_type_window2.addWidget(self.second_canal_check)
    self.stimulation_type_window2.addWidget(self.stim_type_cell2)
    self.canal_window.addLayout(self.stimulation_type_window2)

    self.different_signals_window2 = QStackedLayout()
    self.canal_window.addLayout(self.different_signals_window2)

    self.third_canal_check = QCheckBox()
    self.third_canal_check.stateChanged.connect(self.canals_to_tree)
    self.third_canal_check.setText("Canal 3")
    # self.canal_window.addWidget(self.third_canal_check)

    self.stim_type_cell3 = QComboBox()
    self.stim_type_cell3.addItem("square")
    self.stim_type_cell3.addItem("random-square")
    self.stim_type_cell3.addItem("Third")
    self.stim_type_cell3.currentIndexChanged.connect(self.type_to_tree)
    self.stimulation_type_window3 = QHBoxLayout()
    self.stimulation_type_window3.addWidget(self.third_canal_check)
    # self.stimulation_type_window3.addWidget(self.stim_type_cell3)
    self.canal_window.addLayout(self.stimulation_type_window3)

    self.different_signals_window3 = QStackedLayout()
    self.canal_window.addLayout(self.different_signals_window3)

    self.stimulation_name_label = QLabel("Stimulation Name")
    self.stimulation_name_cell = QLineEdit()
    self.stimulation_name_cell.textEdited.connect(self.name_to_tree)
    self.stimulation_name_window = QHBoxLayout()
    self.stimulation_name_window.addWidget(self.stimulation_name_label)
    self.stimulation_name_window.addWidget(self.stimulation_name_cell)
    self.stimulation_edit_layout.addLayout(self.stimulation_name_window)

    self.duration_window = QHBoxLayout()
    self.first_signal_type_duration_label = QLabel("Duration (s)")
    self.duration_window.addWidget(self.first_signal_type_duration_label)
    self.duration_cell = QLineEdit()
    self.duration_window.addWidget(self.duration_cell)
    self.duration_cell.setValidator(self.onlyFloat)
    self.duration_cell.textEdited.connect(self.signal_to_tree)
    self.stimulation_edit_layout.addLayout(self.duration_window)

    self.baseline_checkbox = QCheckBox("Baseline")
    self.baseline_checkbox.stateChanged.connect(self.canals_to_tree)
    if self.acquisition_mode:
        self.stimulation_edit_layout.addWidget(self.baseline_checkbox)
    self.stimulation_edit_layout.addLayout(self.canal_window)

    self.first_signal_type_window = QVBoxLayout()
    self.first_signal_type_window.setAlignment(Qt.AlignLeft)
    self.first_signal_type_window.setAlignment(Qt.AlignTop)
    self.first_signal_type_window.setContentsMargins(0, 0, 0, 0)
    self.first_signal_type_container = QWidget()
    self.first_signal_type_container.setLayout(self.first_signal_type_window)

    self.first_signal_type_window2 = QVBoxLayout()
    self.first_signal_type_window2.setAlignment(Qt.AlignLeft)
    self.first_signal_type_window2.setAlignment(Qt.AlignTop)
    self.first_signal_type_window2.setContentsMargins(0, 0, 0, 0)
    self.first_signal_type_container2 = QWidget()
    self.first_signal_type_container2.setLayout(self.first_signal_type_window2)

    self.first_signal_type_window3 = QVBoxLayout()
    self.first_signal_type_window3.setAlignment(Qt.AlignLeft)
    self.first_signal_type_window3.setAlignment(Qt.AlignTop)
    self.first_signal_type_window3.setContentsMargins(0, 0, 0, 0)
    self.first_signal_type_container3 = QWidget()
    self.first_signal_type_container3.setLayout(self.first_signal_type_window3)

    self.pulses_window = QHBoxLayout()
    self.pulses_label = QLabel("Pulses")
    self.pulses_window.addWidget(self.pulses_label)
    self.pulses_cell = QLineEdit()
    self.pulses_cell.setValidator(QIntValidator())
    self.pulses_cell.textEdited.connect(self.signal_to_tree)
    self.pulses_window.addWidget(self.pulses_cell)

    self.pulses_window2 = QHBoxLayout()
    self.pulses_label2 = QLabel("Pulses")
    self.pulses_window2.addWidget(self.pulses_label2)
    self.pulses_cell2 = QLineEdit()
    self.pulses_cell2.setValidator(QIntValidator())
    self.pulses_cell2.textEdited.connect(self.signal_to_tree)
    self.pulses_window2.addWidget(self.pulses_cell2)

    self.pulses_window3 = QHBoxLayout()
    self.pulses_label3 = QLabel("Pulses")
    self.pulses_window3.addWidget(self.pulses_label3)
    self.pulses_cell3 = QLineEdit()
    self.pulses_cell3.setValidator(QIntValidator())
    self.pulses_cell3.textEdited.connect(self.signal_to_tree)
    self.pulses_window3.addWidget(self.pulses_cell3)

    self.jitter_window = QHBoxLayout()
    self.jitter_label = QLabel("Jitter (s)")
    self.jitter_window.addWidget(self.jitter_label)
    self.jitter_cell = QLineEdit()
    self.jitter_cell.setValidator(self.onlyFloat)
    self.jitter_cell.setText("0")
    self.jitter_cell.textEdited.connect(self.signal_to_tree)
    self.jitter_window.addWidget(self.jitter_cell)

    self.jitter_window2 = QHBoxLayout()
    self.jitter_window2 = QHBoxLayout()
    self.jitter_label2 = QLabel("Jitter (s)")
    self.jitter_window2.addWidget(self.jitter_label2)
    self.jitter_cell2 = QLineEdit()
    self.jitter_cell2.setValidator(self.onlyFloat)
    self.jitter_cell2.setText("0")
    self.jitter_cell2.textEdited.connect(self.signal_to_tree)
    self.jitter_window2.addWidget(self.jitter_cell2)

    self.jitter_window3 = QHBoxLayout()
    self.jitter_window3 = QHBoxLayout()
    self.jitter_label3 = QLabel("Jitter (s)")
    self.jitter_window3.addWidget(self.jitter_label3)
    self.jitter_cell3 = QLineEdit()
    self.jitter_cell3.setValidator(self.onlyFloat)
    self.jitter_cell3.setText("0")
    self.jitter_cell3.textEdited.connect(self.signal_to_tree)
    self.jitter_window3.addWidget(self.jitter_cell3)

    self.width_window = QHBoxLayout()
    self.width_label = QLabel("Width (s)")
    self.width_window.addWidget(self.width_label)
    self.width_cell = QLineEdit()
    self.width_cell.setValidator(self.onlyFloat)
    self.width_cell.setText("0")
    self.width_cell.textEdited.connect(self.signal_to_tree)
    self.width_window.addWidget(self.width_cell)

    self.width_window2 = QHBoxLayout()
    self.width_label2 = QLabel("Width (s)")
    self.width_window2.addWidget(self.width_label2)
    self.width_cell2 = QLineEdit()
    self.width_cell2.setValidator(self.onlyFloat)
    self.width_cell2.setText("0")
    self.width_cell2.textEdited.connect(self.signal_to_tree)
    self.width_window2.addWidget(self.width_cell2)

    self.width_window3 = QHBoxLayout()
    self.width_label3 = QLabel("Width (s)")
    self.width_window3.addWidget(self.width_label3)
    self.width_cell3 = QLineEdit()
    self.width_cell3.setValidator(self.onlyFloat)
    self.width_cell3.setText("0")
    self.width_cell3.textEdited.connect(self.signal_to_tree)
    self.width_window3.addWidget(self.width_cell3)

    self.first_signal_type_window.addLayout(self.pulses_window)
    self.first_signal_type_window.addLayout(self.width_window)
    self.first_signal_type_window.addLayout(self.jitter_window)

    self.first_signal_type_window2.addLayout(self.pulses_window2)
    self.first_signal_type_window2.addLayout(self.width_window2)
    self.first_signal_type_window2.addLayout(self.jitter_window2)

    self.first_signal_type_window3.addLayout(self.pulses_window3)
    self.first_signal_type_window3.addLayout(self.width_window3)
    self.first_signal_type_window3.addLayout(self.jitter_window3)
    # -------------------

    self.second_signal_type_window = QVBoxLayout()
    self.second_signal_type_container = QWidget()
    self.second_signal_type_window.setAlignment(Qt.AlignLeft)
    self.second_signal_type_window.setAlignment(Qt.AlignTop)
    self.second_signal_type_window.setContentsMargins(0, 0, 0, 0)
    self.second_signal_type_container.setLayout(self.second_signal_type_window)
    # self.stimulation_edit_layout.addLayout(self.different_signals_window)

    self.second_signal_type_window2 = QVBoxLayout()
    self.second_signal_type_container2 = QWidget()
    self.second_signal_type_window2.setAlignment(Qt.AlignLeft)
    self.second_signal_type_window2.setAlignment(Qt.AlignTop)
    self.second_signal_type_window2.setContentsMargins(0, 0, 0, 0)
    self.second_signal_type_container2.setLayout(self.second_signal_type_window2)

    self.second_signal_type_window3 = QVBoxLayout()
    self.second_signal_type_container3 = QWidget()
    self.second_signal_type_window3.setAlignment(Qt.AlignLeft)
    self.second_signal_type_window3.setAlignment(Qt.AlignTop)
    self.second_signal_type_window3.setContentsMargins(0, 0, 0, 0)
    self.second_signal_type_container3.setLayout(self.second_signal_type_window3)

    self.heigth_window = QHBoxLayout()
    self.heigth_label = QLabel("Heigth (V)")
    self.heigth_window.addWidget(self.heigth_label)
    self.heigth_cell = QLineEdit()
    self.heigth_cell.setValidator(self.onlyFloat)
    self.heigth_cell.textEdited.connect(self.signal_to_tree)
    self.heigth_window.addWidget(self.heigth_cell)

    self.heigth_window2 = QHBoxLayout()
    self.heigth_label2 = QLabel("Heigth (V)")
    self.heigth_window2.addWidget(self.heigth_label2)
    self.heigth_cell2 = QLineEdit()
    self.heigth_cell2.setValidator(self.onlyFloat)
    self.heigth_cell2.textEdited.connect(self.signal_to_tree)
    self.heigth_window2.addWidget(self.heigth_cell2)

    self.heigth_window3 = QHBoxLayout()
    self.heigth_label3 = QLabel("Heigth (V)")
    self.heigth_window3.addWidget(self.heigth_label3)
    self.heigth_cell3 = QLineEdit()
    self.heigth_cell3.setValidator(self.onlyFloat)
    self.heigth_cell3.textEdited.connect(self.signal_to_tree)
    self.heigth_window3.addWidget(self.heigth_cell3)

    self.frequency_window = QHBoxLayout()
    self.frequency_label = QLabel("Frequency (Hz)")
    self.frequency_window.addWidget(self.frequency_label)
    self.frequency_cell = QLineEdit()
    self.frequency_cell.setValidator(self.onlyFloat)
    self.frequency_cell.textEdited.connect(self.signal_to_tree)
    self.frequency_window.addWidget(self.frequency_cell)

    self.frequency_window2 = QHBoxLayout()
    self.frequency_label2 = QLabel("Frequency (Hz)")
    self.frequency_window2.addWidget(self.frequency_label2)
    self.frequency_cell2 = QLineEdit()
    self.frequency_cell2.setValidator(self.onlyFloat)
    self.frequency_cell2.textEdited.connect(self.signal_to_tree)
    self.frequency_window2.addWidget(self.frequency_cell2)

    self.frequency_window3 = QHBoxLayout()
    self.frequency_label3 = QLabel("Frequency (Hz)")
    self.frequency_window3.addWidget(self.frequency_label3)
    self.frequency_cell3 = QLineEdit()
    self.frequency_cell3.setValidator(self.onlyFloat)
    self.frequency_cell3.textEdited.connect(self.signal_to_tree)
    self.frequency_window3.addWidget(self.frequency_cell3)

    self.duty_window = QHBoxLayout()
    self.duty_label = QLabel("Duty (%)")
    self.duty_window.addWidget(self.duty_label)
    self.duty_cell = QLineEdit()
    self.duty_cell.setValidator(self.onlyFloat)
    self.duty_cell.textEdited.connect(self.signal_to_tree)
    self.duty_window.addWidget(self.duty_cell)

    self.duty_window2 = QHBoxLayout()
    self.duty_label2 = QLabel("Duty (%)")
    self.duty_window2.addWidget(self.duty_label2)
    self.duty_cell2 = QLineEdit()
    self.duty_cell2.setValidator(self.onlyFloat)
    self.duty_cell2.textEdited.connect(self.signal_to_tree)
    self.duty_window2.addWidget(self.duty_cell2)

    self.duty_window3 = QHBoxLayout()
    self.duty_label3 = QLabel("Duty (%)")
    self.duty_window3.addWidget(self.duty_label3)
    self.duty_cell3 = QLineEdit()
    self.duty_cell3.setValidator(self.onlyFloat)
    self.duty_cell3.textEdited.connect(self.signal_to_tree)
    self.duty_window3.addWidget(self.duty_cell3)

    self.second_signal_type_window.addLayout(self.heigth_window)
    self.second_signal_type_window.addLayout(self.frequency_window)
    self.second_signal_type_window.addLayout(self.duty_window)

    self.second_signal_type_window2.addLayout(self.heigth_window2)
    self.second_signal_type_window2.addLayout(self.frequency_window2)
    self.second_signal_type_window2.addLayout(self.duty_window2)

    # self.second_signal_type_window3.addLayout(self.heigth_window3)
    self.second_signal_type_window3.addLayout(self.frequency_window3)
    self.second_signal_type_window3.addLayout(self.duty_window3)

    # -------------------

    self.third_signal_type_window = QVBoxLayout()
    self.third_signal_type_container = QWidget()
    self.third_signal_type_container.setLayout(self.third_signal_type_window)

    self.third_signal_type_window2 = QVBoxLayout()
    self.third_signal_type_container2 = QWidget()
    self.third_signal_type_container2.setLayout(self.third_signal_type_window2)

    self.third_signal_type_window3 = QVBoxLayout()
    self.third_signal_type_container3 = QWidget()
    self.third_signal_type_container3.setLayout(self.third_signal_type_window3)

    self.third_signal_type_name = QLabel("signal3")
    self.third_signal_type_window.addWidget(self.third_signal_type_name)

    self.third_signal_type_name2 = QLabel("signal3")
    self.third_signal_type_window2.addWidget(self.third_signal_type_name2)

    self.third_signal_type_name3 = QLabel("signal3")
    self.third_signal_type_window3.addWidget(self.third_signal_type_name3)

    self.different_signals_window.addWidget(self.second_signal_type_container)
    self.different_signals_window.addWidget(self.first_signal_type_container)
    self.different_signals_window.addWidget(self.third_signal_type_container)

    self.different_signals_window2.addWidget(self.second_signal_type_container2)
    self.different_signals_window2.addWidget(self.first_signal_type_container2)
    self.different_signals_window2.addWidget(self.third_signal_type_container2)

    self.different_signals_window3.addWidget(self.second_signal_type_container3)
    self.different_signals_window3.addWidget(self.first_signal_type_container3)
    self.different_signals_window3.addWidget(self.third_signal_type_container3)

    self.stimulation_edit_container = QWidget()
    self.stimulation_edit_container.setLayout(self.stimulation_edit_layout)
    self.block_edit_layout = QVBoxLayout()
    self.block_edit_layout.setContentsMargins(0, 0, 0, 0)
    self.block_edit_layout.setAlignment(Qt.AlignLeft)
    self.block_edit_layout.setAlignment(Qt.AlignTop)

    self.block_name_label = QLabel("Block Name")
    self.block_name_cell = QLineEdit()
    self.block_name_cell.textEdited.connect(self.name_to_tree)
    self.block_name_window = QHBoxLayout()
    self.block_name_window.addWidget(self.block_name_label)
    self.block_name_window.addWidget(self.block_name_cell)
    self.block_edit_layout.addLayout(self.block_name_window)

    self.block_iterations_window = QHBoxLayout()
    self.block_iterations_label = QLabel("Iterations")
    self.block_iterations_cell = QLineEdit()
    self.block_iterations_cell.setValidator(QIntValidator())
    self.block_iterations_cell.textEdited.connect(self.block_to_tree)
    self.block_iterations_window.addWidget(self.block_iterations_label)
    self.block_iterations_window.addWidget(self.block_iterations_cell)
    self.block_edit_layout.addLayout(self.block_iterations_window)

    self.block_delay_window = QHBoxLayout()
    self.block_delay_label = QLabel("Delay")
    self.block_delay_cell = QLineEdit()
    self.block_delay_cell.setValidator(self.onlyFloat)
    self.block_delay_cell.textEdited.connect(self.block_to_tree)
    self.block_delay_window = QHBoxLayout()
    self.block_delay_window.addWidget(self.block_delay_label)
    self.block_delay_window.addWidget(self.block_delay_cell)
    self.block_edit_layout.addLayout(self.block_delay_window)

    self.block_jitter_window = QHBoxLayout()
    self.block_jitter_label = QLabel("Jitter")
    self.block_jitter_cell = QLineEdit()
    self.block_jitter_cell.setValidator(self.onlyFloat)
    self.block_jitter_cell.textEdited.connect(self.block_to_tree)
    self.block_jitter_window = QHBoxLayout()
    self.block_jitter_window.addWidget(self.block_jitter_label)
    self.block_jitter_window.addWidget(self.block_jitter_cell)
    self.block_edit_layout.addLayout(self.block_jitter_window)

    self.block_edit_container = QWidget()
    self.block_edit_container.setLayout(self.block_edit_layout)
    self.signal_adjust_superposed.addWidget(self.stimulation_edit_container)
    self.signal_adjust_superposed.addWidget(self.block_edit_container)
    self.signal_adjust_superposed.addWidget(QLabel())
    self.signal_adjust_superposed.setCurrentIndex(2)
    self.grid_layout.addLayout(self.signal_adjust_superposed, 3, 1)

    self.signal_preview_label = QLabel("Signal Preview")
    self.signal_preview_label.setFont(QFont("IBM Plex Sans", 17))
    if self.acquisition_mode:
        self.grid_layout.addWidget(self.signal_preview_label, 2, 2)
    else:
        self.grid_layout.addWidget(self.signal_preview_label, 0, 2)

    self.buttons_main_window = QHBoxLayout()
    self.stop_button = QPushButton("Stop")
    self.stop_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "player-stop.png"))
    )
    self.stop_button.clicked.connect(self.stop_while_running)
    self.stop_button.setEnabled(False)
    self.buttons_main_window.addWidget(self.stop_button)
    self.run_button = QPushButton("Run")
    self.run_button.setIcon(
        QIcon(os.path.join(self.cwd, "gui", "icons", "player-play.png"))
    )
    self.run_button.clicked.connect(self.run)
    self.run_button.setEnabled(False)
    self.buttons_main_window.addWidget(self.run_button)
    self.plot_window = PlotWindow(subplots=True)
    if self.acquisition_mode:
        self.grid_layout.addWidget(self.plot_window, 3, 2)
    else:
        self.grid_layout.addWidget(self.plot_window, 1, 2, 3, 1)
    self.grid_layout.addLayout(self.buttons_main_window, 4, 2)
    self.open_daq_generation_thread()
    self.initialize_buttons()
    self.show()
def initialize_buttons(self)

Define list of buttons to activate/deactivate

Expand source code
def initialize_buttons(self):
    """Define list of buttons to activate/deactivate"""
    self.canal1buttons = [
        self.stim_type_cell,
        self.pulses_label,
        self.pulses_cell,
        self.width_label,
        self.width_cell,
        self.jitter_label,
        self.jitter_cell,
        self.frequency_label,
        self.frequency_cell,
        self.duty_label,
        self.duty_cell,
        self.heigth_cell,
        self.heigth_label,
    ]
    self.canal2buttons = [
        self.stim_type_cell2,
        self.pulses_label2,
        self.pulses_cell2,
        self.width_label2,
        self.width_cell2,
        self.jitter_label2,
        self.jitter_cell2,
        self.frequency_label2,
        self.frequency_cell2,
        self.duty_label2,
        self.duty_cell2,
        self.heigth_cell2,
        self.heigth_label2,
    ]
    self.canal3buttons = [
        self.stim_type_cell3,
        self.pulses_label3,
        self.pulses_cell3,
        self.width_label3,
        self.width_cell3,
        self.jitter_label3,
        self.jitter_cell3,
        self.frequency_label3,
        self.frequency_cell3,
        self.duty_label3,
        self.duty_cell3,
        self.heigth_cell3,
        self.heigth_label3,
    ]
    self.enabled_buttons = [
        self.run_button,
        self.experiment_name_cell,
        self.mouse_id_cell,
        self.directory_choose_button,
        self.set_roi_button,
        self.reset_roi_button,
        self.experiment_name,
        self.mouse_id_label,
        self.framerate_label,
        self.framerate_cell,
        self.exposure_cell,
        self.exposure_label,
        self.add_brother_branch_button,
        self.add_child_branch_button,
        self.delete_item_button,
        self.red_checkbox,
        self.ir_checkbox,
        self.green_checkbox,
        self.fluorescence_checkbox,
        self.stimulation_name_label,
        self.directory_save_files_checkbox,
        self.stimulation_name_cell,
        self.stim_type_cell,
        self.stim_type_cell2,
        self.first_canal_check,
        self.second_canal_check,
        self.first_signal_type_duration_label,
        self.duration_cell,
        self.pulses_label,
        self.pulses_cell,
        self.width_label,
        self.width_cell,
        self.jitter_label,
        self.jitter_cell,
        self.frequency_label,
        self.frequency_cell,
        self.heigth_label,
        self.heigth_cell,
        self.duty_label,
        self.duty_cell,
        self.pulses_label2,
        self.pulses_cell2,
        self.width_label2,
        self.width_cell2,
        self.jitter_label2,
        self.jitter_cell2,
        self.frequency_label2,
        self.frequency_cell2,
        self.heigth_label2,
        self.heigth_cell2,
        self.duty_label2,
        self.duty_cell2,
        self.third_canal_check,
        self.stim_type_cell3,
        self.pulses_label3,
        self.pulses_cell3,
        self.width_label3,
        self.width_cell3,
        self.jitter_label3,
        self.jitter_cell3,
        self.frequency_label3,
        self.frequency_cell3,
        self.duty_label3,
        self.duty_cell3,
        self.heigth_cell3,
        self.heigth_label3,
        self.block_iterations_label,
        self.block_iterations_cell,
        self.block_delay_label,
        self.block_delay_cell,
        self.block_jitter_label,
        self.block_jitter_cell,
        self.block_name_label,
        self.block_name_cell,
        self.activate_live_preview_button,
        self.deactivate_live_preview_button,
        self.tree,
    ]
def live_save(self)

Save NPY chunked files when the number of frames is over 1200

Expand source code
def live_save(self):
    """Save NPY chunked files when the number of frames is over 1200"""
    self.camera.file_index = 0
    self.camera.is_saving = False
    if self.directory_save_files_checkbox.isChecked():
        try:
            os.mkdir(
                os.path.join(
                    self.directory_cell.text(), self.experiment_name_cell.text()
                )
            )
            os.mkdir(
                os.path.join(
                    self.directory_cell.text(),
                    self.experiment_name_cell.text(),
                    "data",
                )
            )
        except Exception as err:
            pass
        while self.camera.video_running is False and not self.camera.stop_signal:
            time.sleep(0.01)
            pass
        while self.camera.video_running is True:
            if len(self.camera.frames) > 1200:
                self.memory = self.camera.frames[:1200]
                self.camera.frames = self.camera.frames[1200:]
                if self.directory_save_files_checkbox.isChecked():
                    try:
                        self.memory = shrink_array(self.memory, self.roi_extent)
                    except Exception:
                        pass
                    self.camera.is_saving = True
                    np.save(
                        os.path.join(
                            self.directory_cell.text(),
                            self.experiment_name_cell.text(),
                            "data",
                            f"{self.camera.file_index}.npy",
                        ),
                        self.memory,
                    )
                    self.memory = None
                    self.camera.file_index += 1
                    self.camera.is_saving = False
            time.sleep(0.01)
def name_to_tree(self)

Transfer the name of the current item from the cell to the tree

Expand source code
def name_to_tree(self):
    """Transfer the name of the current item from the cell to the tree"""
    branch = self.tree.currentItem()
    branch.setForeground(0, QBrush(QColor(0, 0, 0)))
    if branch.childCount() > 0:
        branch.setText(0, self.block_name_cell.text())
    else:
        branch.setText(0, self.stimulation_name_cell.text())
def open_baseline_check_thread(self)

Open the thread for the baseline check

Expand source code
def open_baseline_check_thread(self):
    """Open the thread for the baseline check"""
    self.baseline_check_thread = Thread(target=self.check_baseline)
    self.baseline_check_thread.start()
def open_daq_generation_thread(self)

Open the thread for the DAQ generation

Expand source code
def open_daq_generation_thread(self):
    """Open the thread for the DAQ generation"""
    self.daq_generation_thread = Thread(target=self.generate_daq)
    self.daq_generation_thread.start()
def open_live_preview_thread(self)

Open the thread for the live preview

Expand source code
def open_live_preview_thread(self):
    """Open the thread for the live preview"""
    self.live_preview_thread = Thread(target=self.start_live)
    self.live_preview_thread.start()
def open_live_saving_thread(self)

Open the thread for the live saving

Expand source code
def open_live_saving_thread(self):
    """Open the thread for the live saving"""
    self.live_save_thread = Thread(target=self.live_save)
    self.live_save_thread.start()
def open_signal_preview_thread(self)

Open the thread for the signal preview

Expand source code
def open_signal_preview_thread(self):
    """Open the thread for the signal preview"""
    self.signal_preview_thread = Thread(target=self.actualize_progression)
    self.signal_preview_thread.start()
def open_start_experiment_thread(self)

Open the thread for the start of the experiment

Expand source code
def open_start_experiment_thread(self):
    """Open the thread for the start of the experiment"""
    self.start_experiment_thread = Thread(target=self.run_stimulation)
    self.start_experiment_thread.start()
def reset_roi(self)

Reset the ROI

Expand source code
def reset_roi(self):
    """Reset the ROI"""
    plt.figure(self.image_view.figure.number)
    plt.xlim(0, int(1024 / self.config["Binning"]))
    plt.ylim(0, int(1024 / self.config["Binning"]))
    self.roi_extent = None
    self.reset_roi_button.setEnabled(False)
def run(self)

Run the experiment

Expand source code
def run(self):
    """Run the experiment"""
    if self.check_override():
        self.deactivate_buttons(buttons=self.enabled_buttons)
        self.master_block = self.tree.create_blocks()
        self.tree.baseline_values = []
        self.tree.graph(item=self.tree.invisibleRootItem())
        self.root_time, self.root_signal = (
            self.tree.x_values,
            [
                self.tree.stim1_values,
                self.tree.stim2_values,
                self.tree.stim3_values,
            ],
        )
        self.draw(root=True)
        if self.acquisition_mode:
            self.actualize_daq()
            self.open_live_saving_thread()
            self.open_live_preview_thread()
            self.open_baseline_check_thread()
        else:
            self.daq.stop_signal = False
        self.open_signal_preview_thread()
        self.open_start_experiment_thread()
def run_stimulation(self)

Run the stimulation in parallel with the lights

Expand source code
def run_stimulation(self):
    """Run the stimulation in parallel with the lights"""
    self.experiment = Experiment(
        self.master_block,
        int(self.framerate_cell.text()),
        int(self.exposure_cell.text()),
        self.mouse_id_cell.text(),
        self.directory_cell.text(),
        self.daq,
        name=self.experiment_name_cell.text(),
        config=self.config,
    )
    self.save_files_after_stop = True
    self.daq.launch(self.experiment.name, self.root_time, self.root_signal)
    # if (
    #    not self.daq.stop_signal
    #    and self.save_files_after_stop
    #    and self.directory_save_files_checkbox.isChecked()
    # ):
    if (
        self.save_files_after_stop
        and self.directory_save_files_checkbox.isChecked()
    ):
        try:
            print("this is the extent")
            print(self.roi_extent)
            self.experiment.save(self.roi_extent)
        except Exception as err:
            print("err after saving first")
            print(err)
            print("err before entering")
            self.experiment.save()
    self.stop()
def save_config(self)

Save the current configuration to a JSON file

Expand source code
def save_config(self):
    """Save the current configuration to a JSON file"""
    folder = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
    if folder != "":
        self.master_block = self.tree.create_blocks()
        self.experiment = Experiment(
            self.master_block,
            int(self.framerate_cell.text()),
            int(self.exposure_cell.text()),
            self.mouse_id_cell.text(),
            folder,
            self.daq,
            name=self.experiment_name_cell.text(),
            config=self.config,
        )
        self.experiment.save_config(
            [int(1024 / self.config["Binning"]), int(1024 / self.config["Binning"])]
        )
def save_roi(self)

Save the ROI

Expand source code
def save_roi(self):
    """Save the ROI"""
    self.activate_buttons(buttons=self.enabled_buttons)
    self.roi_buttons.setCurrentIndex(0)
    plt.figure(self.image_view.figure.number)
    plt.ion()
    print(self.roi_extent)
    plt.xlim(self.roi_extent[0], self.roi_extent[1])
    plt.ylim(self.roi_extent[2], self.roi_extent[3])
    self.rect_selector.clear()
    self.rect_selector = None
    self.reset_roi_button.setEnabled(True)
def set_lights(self, lights)

Set the lights

Expand source code
def set_lights(self, lights):
    """Set the lights"""
    for light in lights:
        if light == "infrared":
            self.ir_checkbox.setChecked(True)
        elif light == "red":
            self.red_checkbox.setChecked(True)
        elif light == "green":
            self.green_checkbox.setChecked(True)
        elif light == "blue":
            self.fluorescence_checkbox.setChecked(True)
def set_roi(self)

Set the ROI

Expand source code
def set_roi(self):
    """Set the ROI"""
    self.deactivate_buttons(buttons=self.enabled_buttons)
    self.stop_button.setEnabled(False)
    self.save_roi_button.setEnabled(False)
    self.roi_buttons.setCurrentIndex(1)

    def onselect_function(eclick, erelease):
        """Save the ROI dimensions as attributes"""
        self.roi_extent = self.rect_selector.extents
        self.save_roi_button.setEnabled(True)

    self.rect_selector = RectangleSelector(
        self.plot_image.axes,
        onselect_function,
        drawtype="box",
        useblit=True,
        button=[1, 3],
        minspanx=5,
        minspany=5,
        spancoords="pixels",
        interactive=True,
    )
def set_trigger(self)

Set the trigger for the DAQ

Expand source code
def set_trigger(self):
    """Set the trigger for the DAQ"""
    if not self.acquisition_mode:
        self.run_button.setText("Run at Trigger")
        self.daq.set_trigger(self.ports["trigger"])
    else:
        self.run_button.setText("Run")
        self.daq.remove_trigger()
def show_buttons(self, buttons)

Show the buttons in a list

Expand source code
def show_buttons(self, buttons):
    """Show the buttons in a list"""
    for button in buttons:
        button.setVisible(True)
def signal_to_tree(self)

Transfer the signal of the current item from the cell to the tree

Expand source code
def signal_to_tree(self):
    """Transfer the signal of the current item from the cell to the tree"""
    self.tree.currentItem().setText(6, self.duration_cell.text())
    self.tree.currentItem().setText(5, self.pulses_cell.text())
    self.tree.currentItem().setText(7, self.jitter_cell.text())
    self.tree.currentItem().setText(8, self.width_cell.text())
    self.tree.currentItem().setText(9, self.frequency_cell.text())
    self.tree.currentItem().setText(10, self.duty_cell.text())
    self.tree.currentItem().setText(21, self.heigth_cell.text())
    self.tree.currentItem().setText(12, self.pulses_cell2.text())
    self.tree.currentItem().setText(13, self.jitter_cell2.text())
    self.tree.currentItem().setText(14, self.width_cell2.text())
    self.tree.currentItem().setText(15, self.frequency_cell2.text())
    self.tree.currentItem().setText(16, self.duty_cell2.text())
    self.tree.currentItem().setText(22, self.heigth_cell2.text())
    self.tree.currentItem().setText(24, self.pulses_cell3.text())
    self.tree.currentItem().setText(25, self.jitter_cell3.text())
    self.tree.currentItem().setText(26, self.width_cell3.text())
    self.tree.currentItem().setText(27, self.frequency_cell3.text())
    self.tree.currentItem().setText(28, self.duty_cell3.text())
    self.enable_run(self.tree.check_global_validity())
    self.tree.graph(self.tree.currentItem(), current=True)
    self.draw()
def start_in_acquisition_mode(self)

Initialize the interface in acquisition mode

Expand source code
def start_in_acquisition_mode(self):
    """Initialize the interface in acquisition mode"""
    self.start_container.setParent(None)
    self.acquisition_mode = True
    self.initUI()
def start_in_trigger_mode(self)

Initialize the interface in trigger mode

Expand source code
def start_in_trigger_mode(self):
    """Initialize the interface in trigger mode"""
    self.start_container.setParent(None)
    self.acquisition_mode = False
    self.initUI()
def start_live(self)

Start the live preview

Expand source code
def start_live(self):
    """Start the live preview"""
    plt.ion()
    self.memory = []
    self.camera.baseline_completed = False
    if len(self.daq.lights) > 0:
        try:
            while self.camera.video_running is False:
                time.sleep(0.01)
                pass
            while self.camera.video_running is True:
                try:
                    if (
                        not self.camera.baseline_completed
                        or self.activation_map_combo.currentIndex() == 0
                    ):
                        self.plot_image.set(
                            array=self.camera.frames[
                                self.live_preview_light_index :: len(
                                    self.daq.lights
                                )
                            ][-1],
                            clim=(0, self.max_exposure),
                            cmap="binary_r",
                        )
                    elif self.activation_map_combo.currentIndex() == 1:
                        start_index = (
                            self.camera.baseline_read_list[0]
                            + self.live_preview_light_index
                        ) % len(self.daq.lights)
                        activation_map = (
                            self.camera.baseline_frames[
                                start_index :: len(self.daq.lights)
                            ][-1]
                            - self.camera.average_baseline[
                                self.live_preview_light_index
                            ]
                        ) / self.camera.average_baseline[
                            self.live_preview_light_index
                        ]
                        self.plot_image.set(
                            array=activation_map,
                            clim=(
                                -self.max_exposure / 200,
                                self.max_exposure / 200,
                            ),
                            cmap="seismic",
                        )
                    else:
                        start_index = (
                            self.camera.baseline_read_list[0]
                            + self.live_preview_light_index
                        ) % len(self.daq.lights)
                        activation_map = np.log(
                            (
                                (
                                    self.camera.baseline_frames[
                                        start_index :: len(self.daq.lights)
                                    ][-1]
                                    - self.camera.average_baseline[
                                        self.live_preview_light_index
                                    ]
                                )
                                / self.camera.average_baseline[
                                    self.live_preview_light_index
                                ]
                            )
                        )
                        self.plot_image.set(
                            array=activation_map,
                            clim=(
                                -self.max_exposure / 2000,
                                self.max_exposure / 2000,
                            ),
                            cmap="seismic",
                        )

                except Exception as err:
                    print(err)
                    pass
                time.sleep(0.04)
        except Exception as err:
            pass
def stop(self)

Stop the experiment and reactivate the interface

Expand source code
def stop(self):
    """Stop the experiment and reactivate the interface"""
    self.stop_live()
    self.activate_buttons(buttons=self.enabled_buttons)
    self.tree.setCurrentItem(self.tree.topLevelItem(0))
    try:
        self.daq.stop_signal = True
    except Exception:
        pass
def stop_live(self)

Stop the live preview

Expand source code
def stop_live(self):
    """Stop the live preview"""
    self.camera.video_running = False
def stop_stimulation_dialog(self)

Ask if user wants to keep the files after experiment is stopped

Expand source code
def stop_stimulation_dialog(self):
    """Ask if user wants to keep the files after experiment is stopped"""
    button = QMessageBox.question(
        self, "Save Files", "Do you want to save the current files?"
    )
    if button == QMessageBox.Yes:
        self.save_files_after_stop = True
    else:
        self.save_files_after_stop = False
def stop_while_running(self)

Stop the experiment while it is running

Expand source code
def stop_while_running(self):
    """Stop the experiment while it is running"""
    if self.directory_save_files_checkbox.isChecked():
        self.stop_stimulation_dialog()
    self.stop()
def tree_to_block(self)

Transfer the block attributes from the tree to the cells

Expand source code
def tree_to_block(self):
    """Transfer the block attributes from the tree to the cells"""
    try:
        self.block_iterations_cell.setText(self.tree.currentItem().text(1))
        self.block_delay_cell.setText(self.tree.currentItem().text(2))
        self.block_jitter_cell.setText(self.tree.currentItem().text(3))
    except Exception:
        pass
def tree_to_canal(self)

Transfer the canals attributes from the tree to the cells

Expand source code
def tree_to_canal(self):
    """Transfer the canals attributes from the tree to the cells"""
    self.canal_running = True
    try:
        self.baseline_checkbox.setChecked(
            self.boolean(self.tree.currentItem().text(17))
        )
        self.first_canal_check.setChecked(
            self.boolean(self.tree.currentItem().text(18))
        )
        self.second_canal_check.setChecked(
            self.boolean(self.tree.currentItem().text(19))
        )
        self.third_canal_check.setChecked(
            self.boolean(self.tree.currentItem().text(30))
        )
        if self.baseline_checkbox.isChecked():
            self.deactivate_buttons(self.canal1buttons + [self.first_canal_check])
            self.deactivate_buttons(self.canal2buttons + [self.second_canal_check])
            self.deactivate_buttons(self.canal3buttons + [self.third_canal_check])
        else:
            self.activate_buttons(
                [
                    self.first_canal_check,
                    self.second_canal_check,
                    self.third_canal_check,
                ]
            )
        if self.first_canal_check.isChecked():
            self.activate_buttons(self.canal1buttons)
        else:
            self.deactivate_buttons(self.canal1buttons)
        if self.second_canal_check.isChecked():
            self.activate_buttons(self.canal2buttons)
        else:
            self.deactivate_buttons(self.canal2buttons)
        if self.third_canal_check.isChecked():
            self.activate_buttons(self.canal3buttons)
        else:
            self.deactivate_buttons(self.canal3buttons)
    except Exception as err:
        pass
    self.canal_running = False
def tree_to_name(self)

Transfer the name of the current item from the tree to the cell

Expand source code
def tree_to_name(self):
    """Transfer the name of the current item from the tree to the cell"""
    try:
        if self.tree.currentItem().childCount() > 0:
            if self.tree.currentItem().text(0) != "No Name":
                self.block_name_cell.setText(self.tree.currentItem().text(0))
            else:
                self.block_name_cell.setText("")
        else:
            if self.tree.currentItem().text(0) != "No Name":
                self.stimulation_name_cell.setText(self.tree.currentItem().text(0))
            else:
                self.stimulation_name_cell.setText("")
    except AttributeError:
        pass
def tree_to_signal(self)

Transfer the signal of the current item from the tree to the cell

Expand source code
def tree_to_signal(self):
    """Transfer the signal of the current item from the tree to the cell"""
    try:
        self.pulses_cell.setText(self.tree.currentItem().text(5))
        self.duration_cell.setText(self.tree.currentItem().text(6))
        self.jitter_cell.setText(self.tree.currentItem().text(7))
        self.width_cell.setText(self.tree.currentItem().text(8))
        self.frequency_cell.setText(self.tree.currentItem().text(9))
        self.heigth_cell.setText(self.tree.currentItem().text(21))
        self.duty_cell.setText(self.tree.currentItem().text(10))
        self.pulses_cell2.setText(self.tree.currentItem().text(12))
        self.jitter_cell2.setText(self.tree.currentItem().text(13))
        self.width_cell2.setText(self.tree.currentItem().text(14))
        self.frequency_cell2.setText(self.tree.currentItem().text(15))
        self.heigth_cell2.setText(self.tree.currentItem().text(22))
        self.duty_cell2.setText(self.tree.currentItem().text(16))
        self.pulses_cell3.setText(self.tree.currentItem().text(24))
        self.jitter_cell3.setText(self.tree.currentItem().text(25))
        self.width_cell3.setText(self.tree.currentItem().text(26))
        self.frequency_cell3.setText(self.tree.currentItem().text(27))
        self.duty_cell3.setText(self.tree.currentItem().text(28))
    except Exception as err:
        pass
def tree_to_type(self)

Transfer the type of the current item from the tree to the cell

Expand source code
def tree_to_type(self):
    """Transfer the type of the current item from the tree to the cell"""
    dico = {"square": 0, "random-square": 1, "Third": 2}
    try:
        self.stim_type_cell.setCurrentIndex(dico[self.tree.currentItem().text(4)])
    except Exception:
        self.stim_type_cell.setCurrentIndex(0)

    try:
        self.stim_type_cell2.setCurrentIndex(dico[self.tree.currentItem().text(11)])
    except Exception:
        self.stim_type_cell2.setCurrentIndex(0)

    try:
        self.stim_type_cell3.setCurrentIndex(dico[self.tree.currentItem().text(23)])
    except Exception:
        self.stim_type_cell3.setCurrentIndex(0)
def type_to_tree(self)

Transfer the type of the current item from the cell to the tree

Expand source code
def type_to_tree(self):
    """Transfer the type of the current item from the cell to the tree"""
    self.enable_run(self.tree.check_global_validity())
    self.different_signals_window.setCurrentIndex(
        self.stim_type_cell.currentIndex()
    )
    self.different_signals_window2.setCurrentIndex(
        self.stim_type_cell2.currentIndex()
    )
    self.different_signals_window3.setCurrentIndex(
        self.stim_type_cell3.currentIndex()
    )
    try:
        self.tree.currentItem().setText(4, str(self.stim_type_cell.currentText()))
    except Exception:
        pass
    try:
        self.tree.currentItem().setText(11, str(self.stim_type_cell2.currentText()))
    except Exception:
        pass
    try:
        self.tree.currentItem().setText(23, str(self.stim_type_cell3.currentText()))
    except Exception:
        pass
    try:
        self.tree.graph(self.tree.currentItem(), current=True)
        self.draw()
    except Exception:
        pass
def verify_exposure(self)

Verify if the exposure/framerate combination is valid

Expand source code
def verify_exposure(self):
    """Verify if the exposure/framerate combination is valid"""
    try:
        boolean_check = (int(self.exposure_cell.text()) / 1000 + 0.0015) * int(
            self.framerate_cell.text()
        ) < 1 and int(self.framerate_cell.text()) <= 57
    except Exception:
        boolean_check = False
    self.exposure_warning_label.setHidden(boolean_check)