from functools import partial
import gc
import os
from pathlib import Path
import platform
import sys
import webbrowser

from natsort import natsorted
import pyqtgraph as pg
from PySide6 import __version__ as pyside6_version
from PySide6 import QtCore, QtGui, QtWidgets

from ...blocks.options import set_global_option
from ...version import __version__ as libversion
from .. import utils
from ..dialogs.bus_database_manager import BusDatabaseManagerDialog
from ..dialogs.dependencies_dlg import DependenciesDlg
from ..dialogs.functions_manager import FunctionsManagerDialog
from ..dialogs.messagebox import MessageBox
from ..dialogs.multi_search import MultiSearch
from ..dialogs.window_selection_dialog import WindowSelectionDialog
from ..ui.main_window import Ui_PyMDFMainWindow
from ..utils import draw_color_icon
from .batch import BatchWidget
from .file import FileWidget
from .mdi_area import get_functions, MdiAreaWidget, WithMDIArea
from .plot import Plot


class MainWindow(WithMDIArea, Ui_PyMDFMainWindow, QtWidgets.QMainWindow):
    def __init__(self, files=None, *args, **kwargs):
        super(Ui_PyMDFMainWindow, self).__init__(*args, **kwargs)
        WithMDIArea.__init__(self, comparison=True)
        self.setupUi(self)
        self._settings = QtCore.QSettings()
        self._settings.setValue("interface/current_theme", self._settings.value("interface/theme", "Light"))
        self._light_palette = self.palette()

        self.ignore_value2text_conversions = self._settings.value("ignore_value2text_conversions", False, type=bool)

        self.display_cg_name = self._settings.value("display_cg_name", False, type=bool)
        self.check_unsaved_display = self._settings.value("check_unsaved_display", True, type=bool)
        self.ignore_invalidation_bits = self._settings.value("ignore_invalidation_bits", False, type=bool)

        self.integer_interpolation = int(
            self._settings.value("mdf/integer_interpolation", "2 - hybrid interpolation")[0]
        )

        self.float_interpolation = int(self._settings.value("mdf/float_interpolation", "1 - linear interpolation")[0])

        self.batch = BatchWidget(
            self.ignore_value2text_conversions,
            self.integer_interpolation,
            self.float_interpolation,
        )
        self.stackedWidget.addWidget(self.batch)

        widget = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout()
        widget.setLayout(layout)

        multi_search = QtWidgets.QPushButton("Search")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/search.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        multi_search.setIcon(icon)
        multi_search.clicked.connect(self.comparison_search)

        multi_info = QtWidgets.QPushButton("Measurements information")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/info.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        multi_info.setIcon(icon)
        multi_info.clicked.connect(self.comparison_info)

        multi_info2 = QtWidgets.QPushButton("Load dsp")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/open.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        multi_info2.setIcon(icon)
        multi_info2.clicked.connect(self.comparison_dsp)

        hbox = QtWidgets.QHBoxLayout()
        hbox.addWidget(multi_search)
        hbox.addWidget(multi_info)
        hbox.addWidget(multi_info2)
        hbox.addStretch()

        self.mdi_area = MdiAreaWidget(parent=self, comparison=True)
        self.mdi_area.add_window_request.connect(self.add_window)
        self.mdi_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        self.mdi_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAsNeeded)

        layout.addLayout(hbox)
        layout.addWidget(self.mdi_area)

        self.stackedWidget.addWidget(widget)
        self.stackedWidget.setCurrentIndex(0)

        self.progress = None

        self.files.tabCloseRequested.connect(self.close_file)
        self.stackedWidget.currentChanged.connect(self.mode_changed)

        menu = self.menubar.addMenu("File")
        open_group = QtGui.QActionGroup(self)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/open.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)

        action = QtGui.QAction(icon, "Open", menu)
        action.triggered.connect(self.open)
        action.setShortcut(QtGui.QKeySequence("Ctrl+O"))
        open_group.addAction(action)

        action = QtGui.QAction(icon, "Open folder", menu)
        action.triggered.connect(self.open_folder)
        open_group.addAction(action)

        menu.addActions(open_group.actions())

        menu.addSeparator()

        open_group = QtGui.QActionGroup(self)
        action = QtGui.QAction(icon, "Open configuration", menu)
        action.triggered.connect(self.open_configuration)
        open_group.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/save.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "Save configuration", menu)
        action.triggered.connect(self.save_configuration)
        open_group.addAction(action)

        menu.addActions(open_group.actions())

        # mode_actions
        mode_actions = QtGui.QActionGroup(self)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/file.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}".format("Single files"), menu)
        action.triggered.connect(partial(self.stackedWidget.setCurrentIndex, 0))
        mode_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/list.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}".format("Batch processing"), menu)
        action.triggered.connect(partial(self.stackedWidget.setCurrentIndex, 1))
        mode_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/compare.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}".format("Comparison"), menu)
        action.triggered.connect(partial(self.stackedWidget.setCurrentIndex, 2))
        mode_actions.addAction(action)

        menu = QtWidgets.QMenu("Mode", self.menubar)
        menu.addActions(mode_actions.actions())
        self.menubar.addMenu(menu)

        # managers
        actions = QtGui.QActionGroup(self)

        action = QtGui.QAction("{: <20}\tF6".format("Functions manager"), menu)
        action.triggered.connect(self.functions_manager)
        action.setShortcut("F6")
        actions.addAction(action)

        action = QtGui.QAction("{: <20}".format("Bus database manager"), menu)
        action.triggered.connect(self.bus_database_manager)
        actions.addAction(action)

        menu = QtWidgets.QMenu("Managers", self.menubar)
        menu.addActions(actions.actions())
        self.menubar.addMenu(menu)

        # settings

        menu = QtWidgets.QMenu("Settings", self.menubar)
        self.menubar.addMenu(menu)

        # sub plots
        subplot_action = QtGui.QAction("Sub-windows", menu)
        subplot_action.setCheckable(True)

        state = self._settings.value("mdf/subwindows", True, type=bool)
        subplot_action.toggled.connect(self.set_subplot_option)
        subplot_action.triggered.connect(self.set_subplot_option)
        subplot_action.setChecked(state)
        menu.addAction(subplot_action)

        # Link sub-windows X-axis
        subplot_action = QtGui.QAction("Link sub-windows X-axis", menu)
        subplot_action.setCheckable(True)
        state = self._settings.value("mdf/subwindows_link", True, type=bool)
        subplot_action.toggled.connect(self.set_subplot_link_option)
        subplot_action.setChecked(state)
        menu.addAction(subplot_action)

        # Ignore value2text conversions
        subplot_action = QtGui.QAction("Ignore value2text conversions", menu)
        subplot_action.setCheckable(True)
        subplot_action.toggled.connect(self.set_ignore_value2text_conversions_option)
        subplot_action.setChecked(self.ignore_value2text_conversions)
        menu.addAction(subplot_action)

        # invalidation bits
        subplot_action = QtGui.QAction("Ignore invalidation bits", menu)
        subplot_action.setCheckable(True)
        subplot_action.toggled.connect(self.set_invalidation_bits_option)
        subplot_action.setChecked(self.ignore_invalidation_bits)
        menu.addAction(subplot_action)

        # Show Channel Group Name
        subplot_action = QtGui.QAction("Display Channel Group Name", menu)
        subplot_action.setCheckable(True)
        subplot_action.toggled.connect(self.set_display_cg_name_option)
        subplot_action.setChecked(self.display_cg_name)
        menu.addAction(subplot_action)

        # cehck for unsaved display file
        subplot_action = QtGui.QAction("Check for unsaved display changes", menu)
        subplot_action.setCheckable(True)
        subplot_action.toggled.connect(self.set_check_unsaved_display)
        subplot_action.setChecked(self.check_unsaved_display)
        menu.addAction(subplot_action)

        # plot background
        plot_background_option = QtGui.QActionGroup(self)

        for option in ("Black", "White"):
            action = QtGui.QAction(option, menu)
            action.setCheckable(True)
            plot_background_option.addAction(action)
            action.triggered.connect(partial(self.set_plot_background, option))

            if option == self._settings.value("plot/background", "Black"):
                action.setChecked(True)
                action.triggered.emit()

        submenu = QtWidgets.QMenu("Plot background", self.menubar)
        submenu.addActions(plot_background_option.actions())
        menu.addMenu(submenu)

        # plot X axis display mode
        plot_xaxis_option = QtGui.QActionGroup(self)

        for option in ("seconds", "time", "date"):
            action = QtGui.QAction(option, menu)
            action.setCheckable(True)
            plot_xaxis_option.addAction(action)
            action.triggered.connect(partial(self.set_plot_xaxis, option))

            if option == self._settings.value("plot/xaxis_units", "seconds"):
                action.setChecked(True)
                action.triggered.emit()

        submenu = QtWidgets.QMenu("Plot X axis", self.menubar)
        submenu.addActions(plot_xaxis_option.actions())
        menu.addMenu(submenu)

        # theme menu
        theme_option = QtGui.QActionGroup(self)

        for option in ("Dark", "Light"):
            action = QtGui.QAction(option, menu)
            action.setCheckable(True)
            theme_option.addAction(action)
            action.triggered.connect(partial(self.set_theme, option))

            if option == self._settings.value("interface/theme", "Light"):
                action.setChecked(True)
                action.triggered.emit()

        submenu = QtWidgets.QMenu("Theme", self.menubar)
        submenu.addActions(theme_option.actions())
        menu.addMenu(submenu)

        # step line connect menu
        step_option = QtGui.QActionGroup(self)

        for option in ("line", "left", "right"):
            icon = QtGui.QIcon()
            icon.addPixmap(
                QtGui.QPixmap(f":/{option}_interconnect.png"),
                QtGui.QIcon.Mode.Normal,
                QtGui.QIcon.State.Off,
            )
            action = QtGui.QAction(icon, option, menu)
            action.setCheckable(True)
            step_option.addAction(action)
            action.triggered.connect(partial(self.set_line_interconnect, option))

            if option == self._settings.value("plot/curve/line_interconnect", "line"):
                action.setChecked(True)
                action.triggered.emit()

        submenu = QtWidgets.QMenu("Step mode", self.menubar)
        submenu.addActions(step_option.actions())
        menu.addMenu(submenu)

        # integer interpolation menu
        theme_option = QtGui.QActionGroup(self)

        for option, tooltip in zip(
            (
                "0 - repeat previous sample",
                "1 - linear interpolation",
                "2 - hybrid interpolation",
            ),
            (
                "",
                "",
                "channels with integer data type (raw values) that have a conversion that outputs float "
                "values will use linear interpolation, otherwise the previous sample is used",
            ),
            strict=False,
        ):
            action = QtGui.QAction(option, menu)
            action.setCheckable(True)
            if tooltip:
                action.setToolTip(tooltip)
            theme_option.addAction(action)
            action.triggered.connect(partial(self.set_integer_interpolation, option))

            if option == self._settings.value("mdf/integer_interpolation", "2 - hybrid interpolation"):
                action.setChecked(True)
                action.triggered.emit()

        submenu = QtWidgets.QMenu("Integer interpolation", self.menubar)
        submenu.addActions(theme_option.actions())
        submenu.setToolTipsVisible(True)
        menu.addMenu(submenu)

        # float interpolation menu
        theme_option = QtGui.QActionGroup(self)

        for option in ("0 - repeat previous sample", "1 - linear interpolation"):
            action = QtGui.QAction(option, menu)
            action.setCheckable(True)
            theme_option.addAction(action)
            action.triggered.connect(partial(self.set_float_interpolation, option))

            if option == self._settings.value("mdf/float_interpolation", "1 - linear interpolation"):
                action.setChecked(True)
                action.triggered.emit()

        submenu = QtWidgets.QMenu("Float interpolation", self.menubar)
        submenu.addActions(theme_option.actions())
        submenu.setToolTipsVisible(True)
        menu.addMenu(submenu)

        # tabular interpolation
        subplot_action = QtGui.QAction("Tabular windows interpolation", menu)
        subplot_action.setCheckable(True)
        state = self._settings.value("tabular/interpolation", True, type=bool)
        subplot_action.toggled.connect(self.set_tabular_interpolation_option)
        subplot_action.setChecked(state)
        menu.addAction(subplot_action)

        submenu = QtWidgets.QMenu("Cursor", self.menubar)

        # cursor

        action = QtGui.QAction("Color")
        action.triggered.connect(partial(self.edit_cursor_options, action=action))
        color = self._settings.value("plot/cursor/color", "white")
        icon = draw_color_icon(color)
        action.setIcon(icon)
        submenu.addAction(action)

        action = QtWidgets.QWidgetAction(submenu)
        action.setText("Line width")
        combo = QtWidgets.QComboBox()
        combo.addItems([f"{size}pixels width" for size in range(1, 5)])
        combo.currentIndexChanged.connect(partial(self.edit_cursor_options, action=action))
        action.setDefaultWidget(combo)

        submenu.addAction(action)

        action = QtGui.QAction("Show circle")
        action.setCheckable(True)
        action.toggled.connect(partial(self.edit_cursor_options, action=action))
        action.setChecked(self._settings.value("show_cursor_circle", False, type=bool))
        submenu.addAction(action)

        action = QtGui.QAction("Show horizontal line")
        action.setCheckable(True)
        action.toggled.connect(partial(self.edit_cursor_options, action=action))
        action.setChecked(self._settings.value("show_cursor_horizontal_line", False, type=bool))
        submenu.addAction(action)

        menu.addMenu(submenu)

        self.edit_cursor_options()

        # plot option menu
        plot_actions = QtGui.QActionGroup(self)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/fit.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        fullscreen = QtGui.QAction(icon, f"{'Fullscreen': <20}\tF11", menu)
        fullscreen.triggered.connect(self.toggle_fullscreen)
        fullscreen.setShortcut(QtCore.Qt.Key.Key_F11)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/fit.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, f"{'Fit all': <20}\tF", menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_F))
        action.setShortcut(QtCore.Qt.Key.Key_F)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/fit.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, f"{'Fit selected': <20}\tShift+F", menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_F, modifier=QtCore.Qt.KeyboardModifier.ShiftModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Shift+F"))
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/grid.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tG".format("Grid"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_G))
        action.setShortcut(QtCore.Qt.Key.Key_G)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/axis.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tH".format("Honeywell"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_H))
        action.setShortcut(QtCore.Qt.Key.Key_H)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/home.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tW".format("Home"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_W))
        action.setShortcut(QtCore.Qt.Key.Key_W)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/list2.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tS".format("Stack all"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_S))
        action.setShortcut(QtCore.Qt.Key.Key_S)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/list2.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+S".format("Stack selected"), menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_S, modifier=QtCore.Qt.KeyboardModifier.ShiftModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Shift+S"))
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/zoom-in.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tI".format("Zoom in"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_I))
        action.setShortcut(QtCore.Qt.Key.Key_I)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/zoom-out.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tO".format("Zoom out"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_O))
        action.setShortcut(QtCore.Qt.Key.Key_O)
        plot_actions.addAction(action)

        action = QtGui.QAction("{: <20}\tX".format("Zoom to range"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_X))
        action.setShortcut(QtCore.Qt.Key.Key_X)
        plot_actions.addAction(action)

        action = QtGui.QAction("{: <20}\t.".format("Toggle dots"), menu)
        action.triggered.connect(partial(self.toggle_dots, key=QtCore.Qt.Key.Key_Period))
        action.setShortcut(QtCore.Qt.Key.Key_Period)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/focus.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\t2".format("Focused mode"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_2))
        action.setShortcut(QtCore.Qt.Key.Key_2)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/plus.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tIns".format("Insert computation"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_Insert))
        action.setShortcut(QtCore.Qt.Key.Key_Insert)
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/save.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+S".format("Save active subplot channels"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_S,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+S"))
        plot_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/save.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+Shift+S".format("Save all subplot channels"), menu)
        action.triggered.connect(self.save_all_subplots)
        action.setShortcut(QtGui.QKeySequence("Ctrl+Shift+S"))
        plot_actions.addAction(action)

        # channel shifting

        channel_shift_actions = QtGui.QActionGroup(self)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/shift_left.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+←".format("Shift channels left"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_Left,
                modifier=QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Shift+Left"))
        channel_shift_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/shift_right.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+→".format("Shift channels right"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_Right,
                modifier=QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Shift+Right"))
        channel_shift_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/shift_up.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+↑".format("Shift channels up"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_Up,
                modifier=QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Shift+Up"))
        channel_shift_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/shift_down.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+↓".format("Shift channels down"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_Down,
                modifier=QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Shift+Down"))
        channel_shift_actions.addAction(action)

        # values display

        display_format_actions = QtGui.QActionGroup(self)

        action = QtGui.QAction("{: <20}\tCtrl+H".format("Hex"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_H,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+H"))
        display_format_actions.addAction(action)

        action = QtGui.QAction("{: <20}\tCtrl+B".format("Bin"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_B,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+B"))
        display_format_actions.addAction(action)

        action = QtGui.QAction("{: <20}\tCtrl+P".format("Physical"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_P,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+P"))
        display_format_actions.addAction(action)

        action = QtGui.QAction("{: <20}\tCtrl+T".format("ASCII"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_T,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+T"))
        display_format_actions.addAction(action)

        # scaled display

        samples_format_actions = QtGui.QActionGroup(self)

        action = QtGui.QAction("{: <20}\tAlt+R".format("Raw samples"), menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_R, modifier=QtCore.Qt.KeyboardModifier.AltModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Alt+R"))
        samples_format_actions.addAction(action)

        action = QtGui.QAction("{: <20}\tAlt+S".format("Scaled samples"), menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_S, modifier=QtCore.Qt.KeyboardModifier.AltModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Alt+S"))
        samples_format_actions.addAction(action)

        # info

        info = QtGui.QActionGroup(self)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/info.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tM".format("Statistics"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_M))
        action.setShortcut(QtGui.QKeySequence("M"))
        info.addAction(action)

        # sub_plots

        subs = QtGui.QActionGroup(self)

        action = QtGui.QAction("{: <20}\tShift+C".format("Cascade sub-windows"), menu)
        action.triggered.connect(partial(self.show_sub_windows, mode="cascade"))
        action.setShortcut(QtGui.QKeySequence("Shift+C"))
        subs.addAction(action)

        action = QtGui.QAction("{: <20}\tShift+T".format("Tile sub-windows in a grid"), menu)
        action.triggered.connect(partial(self.show_sub_windows, mode="tile"))
        action.setShortcut(QtGui.QKeySequence("Shift+T"))
        subs.addAction(action)

        action = QtGui.QAction("{: <20}\tShift+V".format("Tile sub-windows vertically"), menu)
        action.triggered.connect(partial(self.show_sub_windows, mode="tile vertically"))
        action.setShortcut(QtGui.QKeySequence("Shift+V"))
        subs.addAction(action)

        action = QtGui.QAction("{: <20}\tShift+H".format("Tile sub-windows horizontally"), menu)
        action.triggered.connect(partial(self.show_sub_windows, mode="tile horizontally"))
        action.setShortcut(QtGui.QKeySequence("Shift+H"))
        subs.addAction(action)

        action = QtGui.QAction("{: <20}\tShift+Alt+F".format("Toggle sub-windows frames"), menu)
        action.triggered.connect(self.toggle_frames)
        action.setShortcut(QtGui.QKeySequence("Shift+Alt+F"))
        subs.addAction(action)

        action = QtGui.QAction("{: <20}\tShift+L".format("Toggle channel list"), menu)
        action.triggered.connect(self.toggle_channels_list)
        action.setShortcut(QtGui.QKeySequence("Shift+L"))
        subs.addAction(action)

        # cursors
        cursors_actions = QtGui.QActionGroup(self)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/cursor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+G".format("Go to time stamp"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_G,
                modifier=QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Shift+G"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/right.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\t←".format("Move cursor left"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_Left))
        action.setShortcut(QtCore.Qt.Key.Key_Left)
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/left.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\t→".format("Move cursor right"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_Right))
        action.setShortcut(QtCore.Qt.Key.Key_Right)
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/arrow_next_higher.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+PgUp".format("Move cursor to next higher"), menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_PageUp, modifier=QtCore.Qt.KeyboardModifier.ControlModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+PgUp"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/arrow_previous_higher.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+Shift+PgUp".format("Move cursor to previous higher"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_PageUp,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier | QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+Shift+PgUp"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/arrow_next_lower.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+PgDown".format("Move cursor to next lower"), menu)
        action.triggered.connect(
            partial(
                self.plot_action, key=QtCore.Qt.Key.Key_PageDown, modifier=QtCore.Qt.KeyboardModifier.ControlModifier
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+PgDown"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/arrow_previous_lower.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+Shift+PgDown".format("Move cursor to previous lower"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_PageDown,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier | QtCore.Qt.KeyboardModifier.ShiftModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+Shift+PgDown"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/right2.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tAlt+→".format("Move cursor to next different value"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_Right,
                modifier=QtCore.Qt.KeyboardModifier.AltModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Alt+Right"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/left2.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tAlt+←".format("Move cursor to previous different value"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_Left,
                modifier=QtCore.Qt.KeyboardModifier.AltModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Alt+Left"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/range.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tR".format("Range"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_R))
        action.setShortcut(QtCore.Qt.Key.Key_R)
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/lock_range.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tY".format("Lock/unlock range"), menu)
        action.triggered.connect(partial(self.plot_action, key=QtCore.Qt.Key.Key_Y))
        action.setShortcut(QtCore.Qt.Key.Key_Y)
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/lock_range.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tShift+Y".format("Swap range lock"), menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_Y, modifier=QtCore.Qt.KeyboardModifier.ShiftModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Shift+Y"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/bookmark.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tCtrl+I".format("Insert bookmark"), menu)
        action.triggered.connect(
            partial(
                self.plot_action,
                key=QtCore.Qt.Key.Key_I,
                modifier=QtCore.Qt.KeyboardModifier.ControlModifier,
            )
        )
        action.setShortcut(QtGui.QKeySequence("Ctrl+I"))
        cursors_actions.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/bookmark.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "{: <20}\tAlt+I".format("Toggle bookmarks"), menu)
        action.triggered.connect(
            partial(self.plot_action, key=QtCore.Qt.Key.Key_I, modifier=QtCore.Qt.KeyboardModifier.AltModifier)
        )
        action.setShortcut(QtGui.QKeySequence("Alt+I"))
        cursors_actions.addAction(action)

        self.plot_menu = QtWidgets.QMenu("Plot", self.menubar)
        self.plot_menu.addAction(fullscreen)
        self.plot_menu.addSeparator()
        self.plot_menu.addActions(plot_actions.actions())
        self.plot_menu.addSeparator()
        submenu = QtWidgets.QMenu("Channel shifting", self.plot_menu)
        submenu.addActions(channel_shift_actions.actions())
        self.plot_menu.addMenu(submenu)
        self.plot_menu.addSeparator()
        submenu = QtWidgets.QMenu("Cursors and bookmarks", self.plot_menu)
        submenu.addActions(cursors_actions.actions())
        self.plot_menu.addMenu(submenu)
        self.plot_menu.addSeparator()
        submenu = QtWidgets.QMenu("Display mode", self.plot_menu)
        submenu.addActions(display_format_actions.actions())
        submenu.addSeparator()
        submenu.addActions(samples_format_actions.actions())
        self.plot_menu.addMenu(submenu)
        self.plot_menu.addSeparator()
        submenu = QtWidgets.QMenu("Windows", self.plot_menu)
        submenu.addActions(subs.actions())
        self.plot_menu.addMenu(submenu)
        self.plot_menu.addSeparator()
        self.plot_menu.addActions(info.actions())
        self.menubar.addMenu(self.plot_menu)

        menu = self.menubar.addMenu("Help")

        open_group = QtGui.QActionGroup(self)
        action = QtGui.QAction("Dependencies", menu)
        action.triggered.connect(partial(DependenciesDlg.show_dependencies, "asammdf"))
        open_group.addAction(action)
        action = QtGui.QAction("Online documentation", menu)
        action.triggered.connect(self.help)
        action.setShortcut(QtGui.QKeySequence("F1"))
        open_group.addAction(action)

        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/info.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        action = QtGui.QAction(icon, "About asammdf-gui", menu)
        action.triggered.connect(self.show_about)
        open_group.addAction(action)
        open_group.addAction(action)

        menu.addActions(open_group.actions())

        self.with_dots = self._settings.value("plot/dots", False, type=bool)
        self.setWindowTitle(f"asammdf {libversion} [PID={os.getpid()}] - Single files")

        self.set_subplot_option(self._settings.value("mdf/subwindows", "Disabled"))
        self.set_subplot_link_option(self._settings.value("mdf/subwindows_link", "Disabled"))
        self.hide_missing_channels = False
        self.hide_disabled_channels = False

        self.allways_accept_dots = False

        if files:
            for name in files:
                self._open_file(name)

        self.setAcceptDrops(True)

        self.show()
        self.fullscreen = None

    def comparison_dsp(self, event=None):
        windows = list(self.mdi_area.subWindowList())
        for window in windows:
            widget = window.widget()

            self.mdi_area.removeSubWindow(window)
            widget.setParent(None)
            widget.close()
            widget.deleteLater()
            window.close()

        import json
        from traceback import format_exc

        file_name, _ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            "Select display file",
            "",
            "Display files (*.dspf)",
            "Display files (*.dspf)",
        )

        if not file_name or Path(file_name).suffix.lower() != ".dspf":
            return

        with open(file_name) as infile:
            info = json.load(infile)

        new_functions = {}

        if "functions" in info:
            for name, definition in info["functions"].items():
                if name in self.functions:
                    if self.functions[name] != definition:
                        new_functions[os.urandom(6).hex()] = {
                            "name": name,
                            "definition": definition,
                        }
                else:
                    new_functions[os.urandom(6).hex()] = {
                        "name": name,
                        "definition": definition,
                    }

        else:
            for window in info["windows"]:
                if window["type"] == "Plot":
                    for name, definition in get_functions(window["configuration"]["channels"]).items():
                        if name in self.functions:
                            if self.functions[name] != definition:
                                new_functions[os.urandom(6).hex()] = {
                                    "name": name,
                                    "definition": definition,
                                }
                        else:
                            new_functions[os.urandom(6).hex()] = {
                                "name": name,
                                "definition": definition,
                            }

        if new_functions or info.get("global_variables", "") != self.global_variables:
            self.update_functions({}, new_functions, f"{self.global_variables}\n{info.get('global_variables', '')}")

        windows = info.get("windows", [])
        for i, window in enumerate(windows, 1):
            try:
                self.load_window(window)
            except:
                print(format_exc())

    def sizeHint(self):
        return QtCore.QSize(1, 1)

    def help(self, event):
        webbrowser.open_new(r"http://asammdf.readthedocs.io/en/master/gui.html")

    def save_all_subplots(self, key):
        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
        elif self.stackedWidget.currentIndex() == 2:
            widget = self
        widget = self.files.currentWidget()
        widget.save_all_subplots()

    def plot_action(self, key, modifier=QtCore.Qt.KeyboardModifier.NoModifier):
        event = QtGui.QKeyEvent(QtCore.QEvent.Type.KeyPress, key, modifier)

        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
            if widget and widget.get_current_widget():
                widget.get_current_widget().keyPressEvent(event)
        elif self.stackedWidget.currentIndex() == 2:
            widget = self
            if widget and widget.get_current_widget():
                widget.get_current_widget().keyPressEvent(event)

        event.accept()

    def toggle_dots(self, key):
        file_widget = self.files.currentWidget()

        if file_widget:
            widget = file_widget.get_current_widget()
            if widget and isinstance(widget, Plot):
                new_setting_has_dots = not file_widget.with_dots

                current_plot = widget
                count = len(current_plot.plot.signals)

                self.with_dots = new_setting_has_dots
                self._settings.setValue("plot/dots", self.with_dots)
                file_widget.set_line_style(with_dots=new_setting_has_dots)
                self.set_line_style(with_dots=self.with_dots)
        else:
            widget = self.get_current_widget()
            if widget and isinstance(widget, Plot):
                self.with_dots = not self.with_dots
                self._settings.setValue("plot/dots", self.with_dots)
                self.set_line_style(with_dots=self.with_dots)

    def show_sub_windows(self, mode):
        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
            if widget:
                if mode == "tile":
                    widget.mdi_area.tileSubWindows()
                elif mode == "cascade":
                    widget.mdi_area.cascadeSubWindows()
                elif mode == "tile vertically":
                    widget.mdi_area.tile_vertically()
                elif mode == "tile horizontally":
                    widget.mdi_area.tile_horizontally()

        else:
            widget = self
            if widget:
                if mode == "tile":
                    widget.mdi_area.tileSubWindows()
                elif mode == "cascade":
                    widget.mdi_area.cascadeSubWindows()
                elif mode == "tile vertically":
                    widget.mdi_area.tile_vertically()
                elif mode == "tile horizontally":
                    widget.mdi_area.tile_horizontally()

    def edit_cursor_options(self, checked=None, action=None):
        if action:
            if action.text() == "Color":
                color = self._settings.value("plot/cursor/color", "white")
                color = QtWidgets.QColorDialog.getColor(color)
                if not color.isValid():
                    return

                self._settings.setValue("plot/cursor/color", color.name())

                icon = draw_color_icon(color)
                action.setIcon(icon)

            elif action.text() == "Show circle":
                self._settings.setValue("show_cursor_circle", action.isChecked())

            elif action.text() == "Show horizontal line":
                self._settings.setValue("show_cursor_horizontal_line", action.isChecked())

            elif action.text() == "Line width":
                self._settings.setValue("plot/cursor/line_width", action.defaultWidget().currentIndex() + 1)

        cursor_circle = self._settings.value("show_cursor_circle", False, type=bool)
        cursor_horizontal_line = self._settings.value("show_cursor_horizontal_line", False, type=bool)
        cursor_line_width = self._settings.value("plot/cursor/line_width", 1, type=int)
        cursor_color = self._settings.value("plot/cursor/color", "#e69138")

        for i in range(self.files.count()):
            file = self.files.widget(i)
            file.set_cursor_options(cursor_circle, cursor_horizontal_line, cursor_line_width, cursor_color)

    def set_subplot_option(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self.set_subplots(state)
        self._settings.setValue("mdf/subwindows", state)

        count = self.files.count()

        for i in range(count):
            self.files.widget(i).set_subplots(state)

    def set_plot_background(self, option):
        self._settings.setValue("plot/background", option)
        if option == "Black":
            pg.setConfigOption("background", "k")
            pg.setConfigOption("foreground", "w")
        else:
            pg.setConfigOption("background", "w")
            pg.setConfigOption("foreground", "k")

    def set_integer_interpolation(self, option):
        self._settings.setValue("mdf/integer_interpolation", option)

        option = int(option[0])
        self.integer_interpolation = option

        count = self.files.count()

        for i in range(count):
            self.files.widget(i).mdf.configure(integer_interpolation=option)

        self.batch.integer_interpolation = option

    def set_float_interpolation(self, option):
        self._settings.setValue("mdf/float_interpolation", option)

        option = int(option[0])
        self.float_interpolation = option

        count = self.files.count()

        for i in range(count):
            self.files.widget(i).mdf.configure(float_interpolation=option)

        self.batch.float_interpolation = option

    def set_plot_xaxis(self, option):
        self._settings.setValue("plot/xaxis_units", option)
        if option == "seconds":
            fmt = "phys"
        elif option == "time":
            fmt = "time"
        elif option == "date":
            fmt = "date"

        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
        elif self.stackedWidget.currentIndex() == 2:
            widget = self
        else:
            widget = None
        if widget:
            plot = widget.get_current_widget()
            if plot and isinstance(plot, Plot):
                widget.get_current_widget().plot.x_axis.format = fmt
                widget.get_current_widget().plot.x_axis.updateAutoSIPrefix()
                if plot.plot.cursor1 is not None:
                    plot.cursor_moved()
                if plot.plot.region is not None:
                    plot.range_modified(plot.plot.region)

    def set_theme(self, option):
        self._settings.setValue("interface/theme", option)
        app = QtWidgets.QApplication.instance()
        if option == "Light":
            app.setPalette(self._light_palette)
        else:
            palette = QtGui.QPalette()
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush)
            brush = QtGui.QBrush(QtGui.QColor(82, 82, 82))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Light, brush)
            brush = QtGui.QBrush(QtGui.QColor(68, 68, 68))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Midlight, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Dark, brush)
            brush = QtGui.QBrush(QtGui.QColor(36, 36, 36))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Mid, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush)
            brush = QtGui.QBrush(QtGui.QColor(100, 100, 100))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.PlaceholderText, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Base, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Window, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Shadow, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.AlternateBase, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 220))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ToolTipBase, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ToolTipText, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush)
            brush = QtGui.QBrush(QtGui.QColor(82, 82, 82))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Light, brush)
            brush = QtGui.QBrush(QtGui.QColor(68, 68, 68))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Midlight, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Dark, brush)
            brush = QtGui.QBrush(QtGui.QColor(36, 36, 36))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Mid, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Base, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Window, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Shadow, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.AlternateBase, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 220))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ToolTipBase, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ToolTipText, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush)
            brush = QtGui.QBrush(QtGui.QColor(82, 82, 82))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Light, brush)
            brush = QtGui.QBrush(QtGui.QColor(68, 68, 68))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Midlight, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Dark, brush)
            brush = QtGui.QBrush(QtGui.QColor(36, 36, 36))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Mid, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush)
            brush = QtGui.QBrush(QtGui.QColor(27, 27, 27))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Base, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Window, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Shadow, brush)
            brush = QtGui.QBrush(QtGui.QColor(55, 55, 55))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.AlternateBase, brush)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 220))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ToolTipBase, brush)
            brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ToolTipText, brush)
            brush = QtGui.QBrush(QtGui.QColor(100, 100, 100))
            brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
            palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Highlight, brush)
            app.setPalette(palette)

    def set_line_interconnect(self, option):
        self._settings.setValue("plot/curve/line_interconnect", option)

        self.line_interconnect = option

        count = self.files.count()

        for i in range(count):
            self.files.widget(i).set_line_interconnect(option)

    def set_subplot_link_option(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self.set_subplots_link(state)
        self._settings.setValue("mdf/subwindows_link", state)
        count = self.files.count()

        for i in range(count):
            self.files.widget(i).set_subplots_link(self.subplots_link)

    def set_tabular_interpolation_option(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self._settings.setValue("tabular/interpolation", state)

    def set_ignore_value2text_conversions_option(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self.ignore_value2text_conversions = state
        self._settings.setValue("ignore_value2text_conversions", state)
        count = self.files.count()

        for i in range(count):
            self.files.widget(i).ignore_value2text_conversions = state
        self.batch.ignore_value2text_conversions = state

    def set_invalidation_bits_option(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self.ignore_invalidation_bits = state
        self._settings.setValue("ignore_invalidation_bits", state)

    def set_check_unsaved_display(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self.check_unsaved_display = state
        self._settings.setValue("check_unsaved_display", state)

        set_global_option("check_unsaved_display_file", state)

    def set_display_cg_name_option(self, state):
        if isinstance(state, str):
            state = True if state == "true" else False
        self.display_cg_name = state
        self._settings.setValue("display_cg_name", state)
        count = self.files.count()

        for i in range(count):
            self.files.widget(i).display_cg_name = state
            if self.files.widget(i).isVisible():
                self.files.widget(i).update_all_channel_trees()

        self.batch.display_cg_name = state

    def update_progress(self, current_index, max_index):
        self.progress = current_index, max_index

    def open_batch_files(self, event):
        file_names, _ = QtWidgets.QFileDialog.getOpenFileNames(
            self,
            "Select measurement file",
            "",
            "CSV (*.csv);;MDF v3 (*.dat *.mdf);;MDF v4(*.mf4);;DL3/ERG files (*.dl3 *.erg);;All files (*.csv *.dat *.mdf *.mf4 *.dl3 *.erg)",
            "All files (*.csv *.dat *.mdf *.mf4 *.dl3 *.erg)",
        )

        if file_names:
            self.batch.files_list.addItems(natsorted(file_names))
            count = self.batch.files_list.count()

            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(":/file.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)

            for row in range(count):
                self.batch.files_list.item(row).setIcon(icon)

    def open(self, event):
        if self.stackedWidget.currentIndex() in (0, 2):
            self.open_file(event)
            self.stackedWidget.setCurrentIndex(0)
        else:
            self.open_batch_files(event)

    def _open_file(self, file_name):
        if isinstance(file_name, (tuple, list)):
            file_names = file_name
        else:
            file_names = [file_name]

        for _file_name in file_names:
            file_name = Path(_file_name)
            index = self.files.count()

            try:
                widget = FileWidget(
                    file_name,
                    self.with_dots,
                    self.subplots,
                    self.subplots_link,
                    self.ignore_value2text_conversions,
                    self.display_cg_name,
                    self.line_interconnect,
                    None,
                    False,
                    False,
                    self,
                    ignore_invalidation_bits=self.ignore_invalidation_bits,
                )

            except:
                raise
            else:
                widget.mdf.configure(integer_interpolation=self.integer_interpolation)
                self.files.addTab(widget, file_name.name)
                self.files.setTabToolTip(index, str(file_name))
                self.files.setCurrentIndex(index)
                widget.open_new_files.connect(self._open_file)
                widget.full_screen_toggled.connect(self.toggle_fullscreen)
                self.edit_cursor_options()

                widget.finalize_init()

    def open_file(self, event):
        system = platform.system().lower()
        if system == "linux":
            # see issue #567
            # file extension is case sensitive on linux
            file_names, _ = QtWidgets.QFileDialog.getOpenFileNames(
                self,
                "Select measurement file",
                self._settings.value("last_opened_path", "", str),
                "CSV (*.csv);;MDF v3 (*.dat *.mdf);;MDF v4(*.mf4 *.mf4z);;DL3/ERG files (*.dl3 *.erg);;All files (*.csv *.dat *.mdf *.mf4 *.mf4z *.dl3 *.erg)",
                "All files (*.csv *.dat *.mdf *.mf4 *.mf4z *.dl3 *.erg)",
                options=QtWidgets.QFileDialog.Option.DontUseNativeDialog,
            )
        else:
            file_names, _ = QtWidgets.QFileDialog.getOpenFileNames(
                self,
                "Select measurement file",
                self._settings.value("last_opened_path", "", str),
                "CSV (*.csv);;MDF v3 (*.dat *.mdf);;MDF v4(*.mf4 *.mf4z);;DL3/ERG files (*.dl3 *.erg);;All files (*.csv *.dat *.mdf *.mf4 *.mf4z *.dl3 *.erg)",
                "All files (*.csv *.dat *.mdf *.mf4 *.mf4z *.dl3 *.erg)",
            )

        if file_names:
            self._settings.setValue("last_opened_path", file_names[0])
            gc.collect()

        for file_name in natsorted(file_names):
            self._open_file(file_name)

    def open_folder(self, event):
        folder = QtWidgets.QFileDialog.getExistingDirectory(
            self,
            "Select folder",
            "",
            QtWidgets.QFileDialog.Option.ShowDirsOnly | QtWidgets.QFileDialog.Option.DontResolveSymlinks,
        )
        if not folder:
            return

        gc.collect()

        if self.stackedWidget.currentIndex() == 0:
            for root, dirs, files in os.walk(folder):
                for file in natsorted(files):
                    if file.lower().endswith((".csv", ".erg", ".dl3", ".dat", ".mdf", ".mf4", ".mf4z")):
                        self._open_file(os.path.join(root, file))
        else:
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(":/file.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)

            self.batch._ignore = True

            for root, dirs, files in os.walk(folder):
                for file in natsorted(files):
                    if file.lower().endswith((".csv", ".erg", ".dl3", ".dat", ".mdf", ".mf4", ".mf4z")):
                        item = QtWidgets.QListWidgetItem(icon, os.path.join(root, file))
                        self.batch.files_list.addItem(item)

            self.batch._ignore = False
            self.batch.update_channel_tree()

    def close_file(self, index):
        widget = self.files.widget(index)
        if widget:
            widget.close()
            widget.setParent(None)
            widget.deleteLater()

        if self.files.count():
            self.files.setCurrentIndex(0)

    def closeEvent(self, event):
        count = self.files.count()
        for i in range(count):
            self.files.widget(i).close()
        if self.fullscreen:
            widget, index = self.fullscreen
            widget.close()
            widget.deleteLater()
        event.accept()

    def dragEnterEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        try:
            if self.stackedWidget.currentIndex() == 0:
                for path in e.mimeData().text().splitlines():
                    path = Path(path.replace(r"file:///", ""))
                    if path.suffix.lower() in utils.SUPPORTED_FILE_EXTENSIONS:
                        self._open_file(path)
            else:
                icon = QtGui.QIcon()
                icon.addPixmap(QtGui.QPixmap(":/file.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)

                for path in e.mimeData().text().splitlines():
                    path = Path(path.replace(r"file:///", ""))
                    if path.suffix.lower() in utils.SUPPORTED_FILE_EXTENSIONS:
                        row = self.batch.files_list.count()
                        self.batch.files_list.addItem(str(path))
                        self.batch.files_list.item(row).setIcon(icon)
        except:
            pass

    def mode_changed(self, index):
        if index == 0:
            self.plot_menu.setEnabled(True)
            self.setWindowTitle(f"asammdf {libversion} [PID={os.getpid()}] - Single files")
        elif index == 1:
            self.plot_menu.setEnabled(False)
            self.setWindowTitle(f"asammdf {libversion} [PID={os.getpid()}] - Batch processing")
        elif index == 2:
            self.plot_menu.setEnabled(True)
            self.setWindowTitle(f"asammdf {libversion} [PID={os.getpid()}] - Comparison")

    def keyPressEvent(self, event):
        key = event.key()
        modifier = event.modifiers()

        if key == QtCore.Qt.Key.Key_F and modifier == QtCore.Qt.KeyboardModifier.ControlModifier:
            if self.files.count() and self.stackedWidget.currentIndex() == 0:
                self.files.currentWidget().keyPressEvent(event)
            elif self.files.count() and self.stackedWidget.currentIndex() == 2:
                event.accept()
                measurements = [file.mdf for file in self.iter_files()]

                dlg = MultiSearch(measurements, parent=self)
                dlg.setModal(True)
                dlg.exec()
                result = dlg.payload
                if result:
                    options = [
                        "New plot window",
                        "New numeric window",
                    ] + [mdi.windowTitle() for mdi in self.mdi_area.subWindowList()]

                    if active_window := self.mdi_area.activeSubWindow():
                        default = active_window.windowTitle()
                    else:
                        default = None

                    dialog = WindowSelectionDialog(options=options, default=default, parent=self)
                    dialog.setModal(True)
                    dialog.exec()

                    if dialog.result():
                        window_type = dialog.selected_type()
                        disable_new_channels = dialog.disable_new_channels()

                        names = []

                        for uuid, (group, ch_index), channel_name in sorted(result):
                            names.append(
                                {
                                    "name": channel_name,
                                    "origin_uuid": uuid,
                                    "type": "channel",
                                    "ranges": [],
                                    "group_index": group,
                                    "channel_index": ch_index,
                                    "uuid": os.urandom(6),
                                    "computed": False,
                                    "computation": {},
                                    "precision": 3,
                                    "common_axis": False,
                                    "individual_axis": False,
                                    "enabled": not disable_new_channels,
                                }
                            )
                        if window_type == "New plot window":
                            self.add_window(["Plot", names])
                        elif window_type == "New numeric window":
                            self.add_window(["Numeric", names])
                        elif window_type == "New tabular window":
                            self.add_window(["Tabular", names])
                        else:
                            for mdi in self.mdi_area.subWindowList():
                                if mdi.windowTitle() == window_type:
                                    self.add_new_channels(names, mdi.widget())
                                    break

        elif key == QtCore.Qt.Key.Key_F11:
            self.toggle_fullscreen()
            event.accept()

        elif key in (QtCore.Qt.Key.Key_F2, QtCore.Qt.Key.Key_F3, QtCore.Qt.Key.Key_F4):
            if self.files.count() and self.stackedWidget.currentIndex() == 0:
                if key == QtCore.Qt.Key.Key_F2:
                    window_type = "Plot"
                elif key == QtCore.Qt.Key.Key_F3:
                    window_type = "Numeric"
                elif key == QtCore.Qt.Key.Key_F4:
                    window_type = "Tabular"
                self.files.currentWidget()._create_window(None, window_type)
            event.accept()

        else:
            super().keyPressEvent(event)

    def comparison_search(self, event):
        event = QtGui.QKeyEvent(
            QtCore.QEvent.Type.KeyPress, QtCore.Qt.Key.Key_F, QtCore.Qt.KeyboardModifier.ControlModifier
        )
        self.keyPressEvent(event)

    def comparison_info(self, event):
        count = self.files.count()
        measurements = [f"{self.files.widget(i).uuid}:\t{self.files.widget(i).mdf.name}" for i in range(count)]

        MessageBox.information(self, "Measurement files used for comparison", "\n".join(measurements))

    def toggle_fullscreen(self):
        if self.files.count() > 0 or self.fullscreen is not None:
            if self.fullscreen is None:
                index = self.files.currentIndex()
                widget = self.files.widget(index)
                if widget:
                    widget.setParent(None)
                    widget.showFullScreen()
                    widget.autofit_sub_plots()
                    self.fullscreen = widget, index
            else:
                widget, index = self.fullscreen
                file_name = str(Path(widget.mdf.name).name)
                self.files.insertTab(index, widget, file_name)
                self.files.setTabToolTip(index, str(widget.mdf.name))
                self.files.setCurrentIndex(index)
                self.fullscreen = None
                self.activateWindow()

                widget.autofit_sub_plots()

                self.with_dots = widget.with_dots
                self._settings.setValue("plot/dots", self.with_dots)

                count = self.files.count()

                for i in range(count):
                    self.files.widget(i).set_line_style(with_dots=self.with_dots)

    def toggle_frames(self, event=None):
        count = self.files.count()

        for i in range(count):
            self.files.widget(i).toggle_frames()

    def toggle_channels_list(self, event=None):
        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
            event = QtGui.QKeyEvent(
                QtCore.QEvent.Type.KeyPress, QtCore.Qt.Key.Key_L, QtCore.Qt.KeyboardModifier.ShiftModifier
            )
            if widget:
                widget.keyPressEvent(event)

    def open_configuration(self, event=None):
        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
            if widget:
                widget.load_channel_list()

    def save_configuration(self, event=None):
        if self.stackedWidget.currentIndex() == 0:
            widget = self.files.currentWidget()
            if widget:
                widget.save_channel_list()

    def functions_manager(self):
        if self.stackedWidget.currentIndex() == 0:
            file = self.files.currentWidget()
            if file:
                channels = {}
                mdf = file.mdf
                for name, entries in mdf.channels_db.items():
                    gp_index, ch_index = entries[0]
                    comment = mdf.groups[gp_index].channels[ch_index].comment

                    channels[name] = comment

                dlg = FunctionsManagerDialog(
                    file.functions, channels, parent=self, global_variables=file.global_variables
                )
                dlg.setModal(True)
                dlg.exec()

                if dlg.pressed_button == "apply":
                    original_definitions = dlg.original_definitions
                    modified_definitions = dlg.modified_definitions

                    if file.global_variables != dlg.global_variables:
                        new_global_variables = dlg.global_variables
                    else:
                        new_global_variables = file.global_variables

                    file.update_functions(
                        original_definitions, modified_definitions, new_global_variables=new_global_variables
                    )

    def bus_database_manager(self):
        dlg = BusDatabaseManagerDialog(parent=self)
        dlg.setModal(True)
        dlg.exec()

        if dlg.pressed_button == "apply":
            dlg.store()

    def show_about(self):
        bits = "x86" if sys.maxsize < 2**32 else "x64"
        cpython = ".".join(str(e) for e in sys.version_info[:3])
        cpython = f"{cpython} {bits}"

        MessageBox.about(
            self,
            "About asammdf-gui",
            f"""Graphical user interface for the asammdf package

* * *

Build information:

*   version {libversion}
*   PySide6 {pyside6_version}
*   CPython {cpython}



Copyright © 2018-2025 Daniel Hrisca""",
            markdown=True,
        )
