From 8f2a3b2d2ba97fdde486fe0fba7f96e9d3979262 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson <oscar.gustafsson@liu.se>
Date: Tue, 4 Feb 2025 08:42:12 +0000
Subject: [PATCH] Qt6 fixes and scheduler class started

---
 .gitlab-ci.yml                         |  60 +-
 b_asic/schedule.py                     | 242 ++++----
 b_asic/scheduler.py                    | 193 ++++++
 b_asic/scheduler_gui/main_window.py    |  12 +-
 b_asic/scheduler_gui/ui_main_window.py | 808 ++++++++++---------------
 pyproject.toml                         |   8 +-
 6 files changed, 656 insertions(+), 667 deletions(-)
 create mode 100644 b_asic/scheduler.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 32946f44..5f4c6f59 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,6 +6,7 @@ before_script:
   - apt-get update --yes
   # - apt-get install --yes build-essential cmake graphviz python3-pyqt5 xvfb xdg-utils lcov
   - apt-get install --yes graphviz python3-pyqt5 xvfb xdg-utils
+  - apt-get install -y libxcb-cursor-dev
   - python -m pip install --upgrade pip
   - python --version
   - pip install -r requirements.txt
@@ -35,53 +36,33 @@ before_script:
         path: cov.xml
   coverage: /(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/
 
-run-test-3.8-pyside2:
-  variables:
-    QT_API: pyside2
-  image: python:3.8
-  extends: ".run-test"
-
-run-test-3.8-pyqt5:
-  variables:
-    QT_API: pyqt5
-  image: python:3.8
-  extends: ".run-test"
-
-run-test-3.9-pyside2:
+run-test-3.10-pyside2:
   variables:
     QT_API: pyside2
-  image: python:3.9
+  image: python:3.10
   extends: ".run-test"
 
-run-test-3.9-pyqt5:
+run-test-3.10-pyqt5:
   variables:
     QT_API: pyqt5
-  image: python:3.9
+  image: python:3.10
   extends: ".run-test"
 
-run-test-3.10-pyside2:
+run-test-3.10-pyqt6:
   variables:
-    QT_API: pyside2
+    QT_API: pyqt6
   image: python:3.10
   extends: ".run-test"
 
-run-test-3.10-pyqt5:
+run-test-3.11-pyqt5:
   variables:
     QT_API: pyqt5
-  image: python:3.10
+  image: python:3.11
   extends: ".run-test"
 
-# PySide2 does not seem to have support for 3.11, "almost works" though
-#run-test-3.11-pyside2:
-#  variables:
-#    QT_API: pyside2
-#  image: python:3.11
-#  extends: ".run-test"
-#  allow_failure: true
-
-run-test-3.11-pyqt5:
+run-test-3.11-pyqt6:
   variables:
-    QT_API: pyqt5
+    QT_API: pyqt6
   image: python:3.11
   extends: ".run-test"
 
@@ -91,20 +72,11 @@ run-test-3.12-pyqt5:
   image: python:3.12
   extends: ".run-test"
 
-# Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?)
-#run-test-3.10-pyside6:
-#  variables:
-#    QT_API: pyside6
-#  image: python:3.10
-#  extends: ".run-test"
-#  allow_failure: true
-#
-#run-test-3.10-pyqt6:
-#  variables:
-#    QT_API: pyqt6
-#  image: python:3.10
-#  extends: ".run-test"
-#  allow_failure: true
+run-test-3.12-pyqt6:
+  variables:
+    QT_API: pyqt6
+  image: python:3.12
+  extends: ".run-test"
 
 run-vhdl-tests:
   variables:
diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 4b34d580..a708fe1a 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -7,7 +7,7 @@ Contains the schedule class for scheduling operations in an SFG.
 import io
 import sys
 from collections import defaultdict
-from typing import Dict, List, Literal, Optional, Sequence, Tuple, cast
+from typing import Dict, List, Optional, Sequence, Tuple, cast
 
 import matplotlib.pyplot as plt
 import numpy as np
@@ -33,6 +33,7 @@ from b_asic.operation import Operation
 from b_asic.port import InputPort, OutputPort
 from b_asic.process import MemoryVariable, OperatorProcess
 from b_asic.resources import ProcessCollection
+from b_asic.scheduler import Scheduler, SchedulingAlgorithm
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
@@ -68,13 +69,8 @@ class Schedule:
         algorithm.
     cyclic : bool, default: False
         If the schedule is cyclic.
-    algorithm : {'ASAP', 'ALAP', 'provided'}, default: 'ASAP'
-        The scheduling algorithm to use. The following algorithm are available:
-
-        * ``'ASAP'``: As-soon-as-possible scheduling.
-        * ``'ALAP'``: As-late-as-possible scheduling.
-
-        If 'provided', use provided *start_times*  and *laps* dictionaries.
+    algorithm : SchedulingAlgorithm, default: 'ASAP'
+        The scheduling algorithm to use.
     start_times : dict, optional
         Dictionary with GraphIDs as keys and start times as values.
         Used when *algorithm* is 'provided'.
@@ -100,7 +96,7 @@ class Schedule:
         sfg: SFG,
         schedule_time: Optional[int] = None,
         cyclic: bool = False,
-        algorithm: Literal["ASAP", "ALAP", "provided"] = "ASAP",
+        algorithm: SchedulingAlgorithm = "ASAP",
         start_times: Optional[Dict[GraphID, int]] = None,
         laps: Optional[Dict[GraphID, int]] = None,
         max_resources: Optional[Dict[TypeName, int]] = None,
@@ -115,10 +111,14 @@ class Schedule:
         self._cyclic = cyclic
         self._y_locations = defaultdict(_y_locations_default)
         self._schedule_time = schedule_time
+
+        self.scheduler = Scheduler(self)
         if algorithm == "ASAP":
-            self._schedule_asap()
+            self.scheduler.schedule_asap()
         elif algorithm == "ALAP":
-            self._schedule_alap()
+            self.scheduler.schedule_alap()
+        elif algorithm == "earliest_deadline":
+            self.scheduler.schedule_earliest_deadline([])
         elif algorithm == "provided":
             if start_times is None:
                 raise ValueError("Must provide start_times when using 'provided'")
@@ -797,116 +797,116 @@ class Schedule:
                 new_sfg = new_sfg.insert_operation_before(op, Delay(), port)
         return new_sfg()
 
-    def _schedule_alap(self) -> None:
-        """Schedule the operations using as-late-as-possible scheduling."""
-        precedence_list = self._sfg.get_precedence_list()
-        self._schedule_asap()
-        max_end_time = self.get_max_end_time()
-
-        if self.schedule_time is None:
-            self._schedule_time = max_end_time
-        elif self.schedule_time < max_end_time:
-            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
-
-        for output in self._sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            self.move_operation_alap(output.graph_id)
-        for step in reversed(precedence_list):
-            graph_ids = {
-                outport.operation.graph_id
-                for outport in step
-                if not isinstance(outport.operation, Delay)
-            }
-            for graph_id in graph_ids:
-                self.move_operation_alap(graph_id)
-
-    def _schedule_asap(self) -> None:
-        """Schedule the operations using as-soon-as-possible scheduling."""
-        precedence_list = self._sfg.get_precedence_list()
-
-        if len(precedence_list) < 2:
-            raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-        non_schedulable_ops = set()
-        for outport in precedence_list[0]:
-            operation = outport.operation
-            if operation.type_name() not in [Delay.type_name()]:
-                if operation.graph_id not in self._start_times:
-                    # Set start time of all operations in the first iter to 0
-                    self._start_times[operation.graph_id] = 0
-            else:
-                non_schedulable_ops.add(operation.graph_id)
-
-        for outport in precedence_list[1]:
-            operation = outport.operation
-            if operation.graph_id not in self._start_times:
-                # Set start time of all operations in the first iter to 0
-                self._start_times[operation.graph_id] = 0
-
-        for outports in precedence_list[2:]:
-            for outport in outports:
-                operation = outport.operation
-                if operation.graph_id not in self._start_times:
-                    # Schedule the operation if it does not have a start time yet.
-                    op_start_time = 0
-                    for current_input in operation.inputs:
-                        if len(current_input.signals) != 1:
-                            raise ValueError(
-                                "Error in scheduling, dangling input port detected."
-                            )
-                        if current_input.signals[0].source is None:
-                            raise ValueError(
-                                "Error in scheduling, signal with no source detected."
-                            )
-                        source_port = current_input.signals[0].source
-
-                        if source_port.operation.graph_id in non_schedulable_ops:
-                            source_end_time = 0
-                        else:
-                            source_op_time = self._start_times[
-                                source_port.operation.graph_id
-                            ]
-
-                            if source_port.latency_offset is None:
-                                raise ValueError(
-                                    f"Output port {source_port.index} of"
-                                    " operation"
-                                    f" {source_port.operation.graph_id} has no"
-                                    " latency-offset."
-                                )
-
-                            source_end_time = (
-                                source_op_time + source_port.latency_offset
-                            )
-
-                        if current_input.latency_offset is None:
-                            raise ValueError(
-                                f"Input port {current_input.index} of operation"
-                                f" {current_input.operation.graph_id} has no"
-                                " latency-offset."
-                            )
-                        op_start_time_from_in = (
-                            source_end_time - current_input.latency_offset
-                        )
-                        op_start_time = max(op_start_time, op_start_time_from_in)
-
-                    self._start_times[operation.graph_id] = op_start_time
-        for output in self._sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
-            if source_port.operation.graph_id in non_schedulable_ops:
-                self._start_times[output.graph_id] = 0
-            else:
-                if source_port.latency_offset is None:
-                    raise ValueError(
-                        f"Output port {source_port.index} of operation"
-                        f" {source_port.operation.graph_id} has no"
-                        " latency-offset."
-                    )
-                self._start_times[output.graph_id] = self._start_times[
-                    source_port.operation.graph_id
-                ] + cast(int, source_port.latency_offset)
-        self._remove_delays()
+    # def _schedule_alap(self) -> None:
+    #     """Schedule the operations using as-late-as-possible scheduling."""
+    #     precedence_list = self._sfg.get_precedence_list()
+    #     self._schedule_asap()
+    #     max_end_time = self.get_max_end_time()
+
+    #     if self.schedule_time is None:
+    #         self._schedule_time = max_end_time
+    #     elif self.schedule_time < max_end_time:
+    #         raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
+
+    #     for output in self._sfg.find_by_type_name(Output.type_name()):
+    #         output = cast(Output, output)
+    #         self.move_operation_alap(output.graph_id)
+    #     for step in reversed(precedence_list):
+    #         graph_ids = {
+    #             outport.operation.graph_id
+    #             for outport in step
+    #             if not isinstance(outport.operation, Delay)
+    #         }
+    #         for graph_id in graph_ids:
+    #             self.move_operation_alap(graph_id)
+
+    # def _schedule_asap(self) -> None:
+    #     """Schedule the operations using as-soon-as-possible scheduling."""
+    #     precedence_list = self._sfg.get_precedence_list()
+
+    #     if len(precedence_list) < 2:
+    #         raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+    #     non_schedulable_ops = set()
+    #     for outport in precedence_list[0]:
+    #         operation = outport.operation
+    #         if operation.type_name() not in [Delay.type_name()]:
+    #             if operation.graph_id not in self._start_times:
+    #                 # Set start time of all operations in the first iter to 0
+    #                 self._start_times[operation.graph_id] = 0
+    #         else:
+    #             non_schedulable_ops.add(operation.graph_id)
+
+    #     for outport in precedence_list[1]:
+    #         operation = outport.operation
+    #         if operation.graph_id not in self._start_times:
+    #             # Set start time of all operations in the first iter to 0
+    #             self._start_times[operation.graph_id] = 0
+
+    #     for outports in precedence_list[2:]:
+    #         for outport in outports:
+    #             operation = outport.operation
+    #             if operation.graph_id not in self._start_times:
+    #                 # Schedule the operation if it does not have a start time yet.
+    #                 op_start_time = 0
+    #                 for current_input in operation.inputs:
+    #                     if len(current_input.signals) != 1:
+    #                         raise ValueError(
+    #                             "Error in scheduling, dangling input port detected."
+    #                         )
+    #                     if current_input.signals[0].source is None:
+    #                         raise ValueError(
+    #                             "Error in scheduling, signal with no source detected."
+    #                         )
+    #                     source_port = current_input.signals[0].source
+
+    #                     if source_port.operation.graph_id in non_schedulable_ops:
+    #                         source_end_time = 0
+    #                     else:
+    #                         source_op_time = self._start_times[
+    #                             source_port.operation.graph_id
+    #                         ]
+
+    #                         if source_port.latency_offset is None:
+    #                             raise ValueError(
+    #                                 f"Output port {source_port.index} of"
+    #                                 " operation"
+    #                                 f" {source_port.operation.graph_id} has no"
+    #                                 " latency-offset."
+    #                             )
+
+    #                         source_end_time = (
+    #                             source_op_time + source_port.latency_offset
+    #                         )
+
+    #                     if current_input.latency_offset is None:
+    #                         raise ValueError(
+    #                             f"Input port {current_input.index} of operation"
+    #                             f" {current_input.operation.graph_id} has no"
+    #                             " latency-offset."
+    #                         )
+    #                     op_start_time_from_in = (
+    #                         source_end_time - current_input.latency_offset
+    #                     )
+    #                     op_start_time = max(op_start_time, op_start_time_from_in)
+
+    #                 self._start_times[operation.graph_id] = op_start_time
+    #     for output in self._sfg.find_by_type_name(Output.type_name()):
+    #         output = cast(Output, output)
+    #         source_port = cast(OutputPort, output.inputs[0].signals[0].source)
+    #         if source_port.operation.graph_id in non_schedulable_ops:
+    #             self._start_times[output.graph_id] = 0
+    #         else:
+    #             if source_port.latency_offset is None:
+    #                 raise ValueError(
+    #                     f"Output port {source_port.index} of operation"
+    #                     f" {source_port.operation.graph_id} has no"
+    #                     " latency-offset."
+    #                 )
+    #             self._start_times[output.graph_id] = self._start_times[
+    #                 source_port.operation.graph_id
+    #             ] + cast(int, source_port.latency_offset)
+    #     self._remove_delays()
 
     def _get_memory_variables_list(self) -> List[MemoryVariable]:
         ret: List[MemoryVariable] = []
diff --git a/b_asic/scheduler.py b/b_asic/scheduler.py
new file mode 100644
index 00000000..845859c9
--- /dev/null
+++ b/b_asic/scheduler.py
@@ -0,0 +1,193 @@
+from enum import Enum
+from typing import TYPE_CHECKING, cast
+
+from b_asic.operation import Operation
+from b_asic.port import OutputPort
+from b_asic.special_operations import Delay, Output
+
+if TYPE_CHECKING:
+    from b_asic.schedule import Schedule
+
+
+class SchedulingAlgorithm(Enum):
+    ASAP = "ASAP"
+    ALAP = "ALAP"
+    EARLIEST_DEADLINE = "earliest_deadline"
+    # LEAST_SLACK = "least_slack" # to be implemented
+    PROVIDED = "provided"
+
+
+class Scheduler:
+    def __init__(self, schedule: "Schedule") -> None:
+        self.schedule = schedule
+
+    def schedule_asap(self) -> None:
+        """Schedule the operations using as-soon-as-possible scheduling."""
+        sched = self.schedule
+        prec_list = sched.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = set()
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.add(operation.graph_id)
+            # elif operation.graph_id not in sched._start_times:
+            else:
+                sched._start_times[operation.graph_id] = 0
+
+        # handle second set in precedence graph (first operations)
+        for outport in prec_list[1]:
+            operation = outport.operation
+            # if operation.graph_id not in sched._start_times:
+            sched._start_times[operation.graph_id] = 0
+
+        # handle the remaining sets
+        for outports in prec_list[2:]:
+            for outport in outports:
+                operation = outport.operation
+                if operation.graph_id not in sched._start_times:
+                    op_start_time = 0
+                    for current_input in operation.inputs:
+                        if len(current_input.signals) != 1:
+                            raise ValueError(
+                                "Error in scheduling, dangling input port detected."
+                            )
+                        if current_input.signals[0].source is None:
+                            raise ValueError(
+                                "Error in scheduling, signal with no source detected."
+                            )
+                        source_port = current_input.signals[0].source
+
+                        if source_port.operation.graph_id in non_schedulable_ops:
+                            source_end_time = 0
+                        else:
+                            source_op_time = sched._start_times[
+                                source_port.operation.graph_id
+                            ]
+
+                            if source_port.latency_offset is None:
+                                raise ValueError(
+                                    f"Output port {source_port.index} of"
+                                    " operation"
+                                    f" {source_port.operation.graph_id} has no"
+                                    " latency-offset."
+                                )
+
+                            source_end_time = (
+                                source_op_time + source_port.latency_offset
+                            )
+
+                        if current_input.latency_offset is None:
+                            raise ValueError(
+                                f"Input port {current_input.index} of operation"
+                                f" {current_input.operation.graph_id} has no"
+                                " latency-offset."
+                            )
+                        op_start_time_from_in = (
+                            source_end_time - current_input.latency_offset
+                        )
+                        op_start_time = max(op_start_time, op_start_time_from_in)
+
+                    sched._start_times[operation.graph_id] = op_start_time
+
+        self._handle_outputs_and_delays(non_schedulable_ops)
+
+    def schedule_alap(self) -> None:
+        """Schedule the operations using as-late-as-possible scheduling."""
+        self.schedule_asap()
+        sched = self.schedule
+        max_end_time = sched.get_max_end_time()
+
+        if sched.schedule_time is None:
+            sched.set_schedule_time(max_end_time)
+        elif sched.schedule_time < max_end_time:
+            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
+
+        # move all outputs ALAP before operations
+        for output in sched.sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            sched.move_operation_alap(output.graph_id)
+
+        # move all operations ALAP
+        for step in reversed(sched.sfg.get_precedence_list()):
+            for outport in step:
+                if not isinstance(outport.operation, Delay):
+                    sched.move_operation_alap(outport.operation.graph_id)
+
+    def schedule_earliest_deadline(
+        self, process_elements: dict[Operation, int]
+    ) -> None:
+        """Schedule the operations using earliest deadline scheduling."""
+
+        # ACT BASED ON THE NUMBER OF PEs!
+
+        sched = self.schedule
+        prec_list = sched.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = set()
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.add(operation.graph_id)
+            elif operation.graph_id not in sched._start_times:
+                sched._start_times[operation.graph_id] = 0
+
+        current_time = 0
+        sorted_outports = sorted(
+            prec_list[1], key=lambda outport: outport.operation.latency
+        )
+        for outport in sorted_outports:
+            op = outport.operation
+            sched._start_times[op.graph_id] = current_time
+            current_time += 1
+
+        for outports in prec_list[2:]:
+            # try all remaining operations for one time step
+            candidates = []
+            current_time -= 1
+            while len(candidates) == 0:
+                current_time += 1
+                for outport in outports:
+                    remaining_op = outport.operation
+                    op_is_ready_to_be_scheduled = True
+                    for op_input in remaining_op.inputs:
+                        source_op = op_input.signals[0].source.operation
+                        source_op_time = sched.start_times[source_op.graph_id]
+                        source_end_time = source_op_time + source_op.latency
+                        if source_end_time > current_time:
+                            op_is_ready_to_be_scheduled = False
+                    if op_is_ready_to_be_scheduled:
+                        candidates.append(remaining_op)
+                        # sched._start_times[remaining_op.graph_id] = current_time
+            sorted_candidates = sorted(
+                candidates, key=lambda candidate: candidate.latency
+            )
+            # schedule the best candidate to current time
+            sched._start_times[sorted_candidates[0].graph_id] = current_time
+
+        self._handle_outputs_and_delays(non_schedulable_ops)
+
+    def _handle_outputs_and_delays(self, non_schedulable_ops) -> None:
+        sched = self.schedule
+        for output in sched._sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
+            if source_port.operation.graph_id in non_schedulable_ops:
+                sched._start_times[output.graph_id] = 0
+            else:
+                if source_port.latency_offset is None:
+                    raise ValueError(
+                        f"Output port {source_port.index} of operation"
+                        f" {source_port.operation.graph_id} has no"
+                        " latency-offset."
+                    )
+                sched._start_times[output.graph_id] = sched._start_times[
+                    source_port.operation.graph_id
+                ] + cast(int, source_port.latency_offset)
+        sched._remove_delays()
diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index bd03b5f2..f4502f99 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -31,7 +31,7 @@ from qtpy.QtCore import (
     Qt,
     Slot,
 )
-from qtpy.QtGui import QCloseEvent, QColor, QFont, QIcon, QIntValidator
+from qtpy.QtGui import QCloseEvent, QColor, QFont, QIcon, QIntValidator, QPalette
 from qtpy.QtWidgets import (
     QAbstractButton,
     QAction,
@@ -1688,8 +1688,16 @@ def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]:
         The edited schedule.
     """
     if not QApplication.instance():
-        QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
         app = QApplication(sys.argv)
+        # Enforce a light palette regardless of laptop theme
+        palette = QPalette()
+        palette.setColor(QPalette.ColorRole.Window, QtCore.Qt.white)
+        palette.setColor(QPalette.ColorRole.WindowText, QtCore.Qt.black)
+        palette.setColor(QPalette.ColorRole.ButtonText, QtCore.Qt.black)
+        palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white)
+        palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray)
+        palette.setColor(QPalette.ColorRole.Text, QtCore.Qt.black)
+        app.setPalette(palette)
     else:
         app = QApplication.instance()
     window = ScheduleMainWindow()
diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py
index ec174369..ad3fa898 100644
--- a/b_asic/scheduler_gui/ui_main_window.py
+++ b/b_asic/scheduler_gui/ui_main_window.py
@@ -1,293 +1,277 @@
-################################################################################
-## Form generated from reading UI file 'main_window.ui'
-##
-## Created by: Qt User Interface Compiler version 5.15.8
-##
-## WARNING! All changes made in this file will be lost when recompiling UI file!
-################################################################################
+# Form implementation generated from reading ui file '.\B-ASIC\b_asic\scheduler_gui\main_window.ui'
+#
+# Created by: PyQt6 UI code generator 6.8.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again.  Do not edit this file unless you know what you are doing.
 
-from qtpy.QtCore import QSize, QCoreApplication, QRect, QMetaObject
-from qtpy.QtGui import QIcon, QColor, QFont, QBrush, Qt, QPainter
-from qtpy.QtWidgets import (
-    QSizePolicy,
-    QAction,
-    QMenu,
-    QMenuBar,
-    QToolBar,
-    QHBoxLayout,
-    QWidget,
-    QGraphicsView,
-    QSplitter,
-    QTableWidgetItem,
-    QTableWidget,
-    QAbstractItemView,
-    QStatusBar,
-)
+
+from qtpy import QtCore, QtGui, QtWidgets
 
 
 class Ui_MainWindow:
     def setupUi(self, MainWindow):
-        if not MainWindow.objectName():
-            MainWindow.setObjectName("MainWindow")
+        MainWindow.setObjectName("MainWindow")
         MainWindow.resize(800, 600)
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QtWidgets.QSizePolicy(
+            QtWidgets.QSizePolicy.Policy.Preferred,
+            QtWidgets.QSizePolicy.Policy.Preferred,
+        )
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
         MainWindow.setSizePolicy(sizePolicy)
-        icon = QIcon()
-        icon.addFile(":/icons/basic/small_logo.png", QSize(), QIcon.Normal, QIcon.Off)
+        icon = QtGui.QIcon()
+        icon.addPixmap(
+            QtGui.QPixmap(":/icons/basic/small_logo.png"),
+            QtGui.QIcon.Mode.Normal,
+            QtGui.QIcon.State.Off,
+        )
         MainWindow.setWindowIcon(icon)
-        self.menu_load_from_file = QAction(MainWindow)
+        self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
+        sizePolicy = QtWidgets.QSizePolicy(
+            QtWidgets.QSizePolicy.Policy.Preferred,
+            QtWidgets.QSizePolicy.Policy.Preferred,
+        )
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(
+            self.centralwidget.sizePolicy().hasHeightForWidth()
+        )
+        self.centralwidget.setSizePolicy(sizePolicy)
+        self.centralwidget.setObjectName("centralwidget")
+        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
+        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
+        self.horizontalLayout.setSpacing(0)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.splitter = QtWidgets.QSplitter(parent=self.centralwidget)
+        self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
+        self.splitter.setHandleWidth(0)
+        self.splitter.setObjectName("splitter")
+        self.view = QtWidgets.QGraphicsView(parent=self.splitter)
+        self.view.setAlignment(
+            QtCore.Qt.AlignmentFlag.AlignLeading
+            | QtCore.Qt.AlignmentFlag.AlignLeft
+            | QtCore.Qt.AlignmentFlag.AlignTop
+        )
+        self.view.setRenderHints(
+            QtGui.QPainter.RenderHint.Antialiasing
+            | QtGui.QPainter.RenderHint.TextAntialiasing
+        )
+        self.view.setViewportUpdateMode(
+            QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate
+        )
+        self.view.setObjectName("view")
+        self.info_table = QtWidgets.QTableWidget(parent=self.splitter)
+        self.info_table.setStyleSheet(
+            "alternate-background-color: #fadefb;background-color: #ebebeb;"
+        )
+        self.info_table.setEditTriggers(
+            QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
+        )
+        self.info_table.setAlternatingRowColors(True)
+        self.info_table.setSelectionBehavior(
+            QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows
+        )
+        self.info_table.setRowCount(2)
+        self.info_table.setColumnCount(2)
+        self.info_table.setObjectName("info_table")
+        item = QtWidgets.QTableWidgetItem()
+        self.info_table.setVerticalHeaderItem(0, item)
+        item = QtWidgets.QTableWidgetItem()
+        self.info_table.setVerticalHeaderItem(1, item)
+        item = QtWidgets.QTableWidgetItem()
+        item.setTextAlignment(
+            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignVCenter
+        )
+        font = QtGui.QFont()
+        font.setBold(False)
+        font.setWeight(50)
+        item.setFont(font)
+        self.info_table.setHorizontalHeaderItem(0, item)
+        item = QtWidgets.QTableWidgetItem()
+        item.setTextAlignment(
+            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignVCenter
+        )
+        self.info_table.setHorizontalHeaderItem(1, item)
+        item = QtWidgets.QTableWidgetItem()
+        font = QtGui.QFont()
+        font.setBold(False)
+        font.setWeight(50)
+        font.setKerning(True)
+        item.setFont(font)
+        brush = QtGui.QBrush(QtGui.QColor(160, 160, 164))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setBackground(brush)
+        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setForeground(brush)
+        item.setFlags(
+            QtCore.Qt.ItemFlag.ItemIsSelectable
+            | QtCore.Qt.ItemFlag.ItemIsEditable
+            | QtCore.Qt.ItemFlag.ItemIsDragEnabled
+            | QtCore.Qt.ItemFlag.ItemIsDropEnabled
+            | QtCore.Qt.ItemFlag.ItemIsUserCheckable
+        )
+        self.info_table.setItem(0, 0, item)
+        item = QtWidgets.QTableWidgetItem()
+        font = QtGui.QFont()
+        font.setBold(False)
+        font.setWeight(50)
+        item.setFont(font)
+        brush = QtGui.QBrush(QtGui.QColor(160, 160, 164))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setBackground(brush)
+        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setForeground(brush)
+        item.setFlags(
+            QtCore.Qt.ItemFlag.ItemIsSelectable
+            | QtCore.Qt.ItemFlag.ItemIsEditable
+            | QtCore.Qt.ItemFlag.ItemIsDragEnabled
+            | QtCore.Qt.ItemFlag.ItemIsDropEnabled
+            | QtCore.Qt.ItemFlag.ItemIsUserCheckable
+        )
+        self.info_table.setItem(1, 0, item)
+        self.info_table.horizontalHeader().setHighlightSections(False)
+        self.info_table.horizontalHeader().setStretchLastSection(True)
+        self.info_table.verticalHeader().setVisible(False)
+        self.info_table.verticalHeader().setDefaultSectionSize(24)
+        self.horizontalLayout.addWidget(self.splitter)
+        MainWindow.setCentralWidget(self.centralwidget)
+        self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20))
+        self.menubar.setObjectName("menubar")
+        self.menuFile = QtWidgets.QMenu(parent=self.menubar)
+        self.menuFile.setObjectName("menuFile")
+        self.menu_Recent_Schedule = QtWidgets.QMenu(parent=self.menuFile)
+        self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule")
+        self.menuView = QtWidgets.QMenu(parent=self.menubar)
+        self.menuView.setObjectName("menuView")
+        self.menu_view_execution_times = QtWidgets.QMenu(parent=self.menuView)
+        self.menu_view_execution_times.setEnabled(False)
+        self.menu_view_execution_times.setObjectName("menu_view_execution_times")
+        self.menu_Edit = QtWidgets.QMenu(parent=self.menubar)
+        self.menu_Edit.setObjectName("menu_Edit")
+        self.menuWindow = QtWidgets.QMenu(parent=self.menubar)
+        self.menuWindow.setObjectName("menuWindow")
+        self.menuHelp = QtWidgets.QMenu(parent=self.menubar)
+        self.menuHelp.setObjectName("menuHelp")
+        MainWindow.setMenuBar(self.menubar)
+        self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
+        self.statusbar.setObjectName("statusbar")
+        MainWindow.setStatusBar(self.statusbar)
+        self.toolBar = QtWidgets.QToolBar(parent=MainWindow)
+        self.toolBar.setObjectName("toolBar")
+        MainWindow.addToolBar(QtCore.Qt.ToolBarArea.TopToolBarArea, self.toolBar)
+        self.menu_load_from_file = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("document-open-folder")
+        self.menu_load_from_file.setIcon(icon)
+        self.menu_load_from_file.setStatusTip("")
         self.menu_load_from_file.setObjectName("menu_load_from_file")
-        icon1 = QIcon()
-        iconThemeName = "document-open-folder"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon1 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon1.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_load_from_file.setIcon(icon1)
-        self.menu_save = QAction(MainWindow)
-        self.menu_save.setObjectName("menu_save")
+        self.menu_save = QtGui.QAction(parent=MainWindow)
         self.menu_save.setEnabled(False)
-        icon2 = QIcon()
-        iconThemeName = "document-save"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon2 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon2.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_save.setIcon(icon2)
-        self.menu_node_info = QAction(MainWindow)
-        self.menu_node_info.setObjectName("menu_node_info")
+        icon = QtGui.QIcon.fromTheme("document-save")
+        self.menu_save.setIcon(icon)
+        self.menu_save.setObjectName("menu_save")
+        self.menu_node_info = QtGui.QAction(parent=MainWindow)
         self.menu_node_info.setCheckable(True)
         self.menu_node_info.setChecked(True)
-        icon3 = QIcon()
-        icon3.addFile(":/icons/misc/right_panel.svg", QSize(), QIcon.Normal, QIcon.Off)
-        icon3.addFile(
-            ":/icons/misc/right_filled_panel.svg", QSize(), QIcon.Normal, QIcon.On
-        )
-        self.menu_node_info.setIcon(icon3)
+        icon1 = QtGui.QIcon()
+        icon1.addPixmap(
+            QtGui.QPixmap(":/icons/misc/right_panel.svg"),
+            QtGui.QIcon.Mode.Normal,
+            QtGui.QIcon.State.Off,
+        )
+        icon1.addPixmap(
+            QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"),
+            QtGui.QIcon.Mode.Normal,
+            QtGui.QIcon.State.On,
+        )
+        self.menu_node_info.setIcon(icon1)
         self.menu_node_info.setIconVisibleInMenu(False)
-        self.menu_quit = QAction(MainWindow)
+        self.menu_node_info.setObjectName("menu_node_info")
+        self.menu_quit = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("application-exit")
+        self.menu_quit.setIcon(icon)
         self.menu_quit.setObjectName("menu_quit")
-        icon4 = QIcon()
-        iconThemeName = "application-exit"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon4 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon4.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_quit.setIcon(icon4)
-        self.menu_save_as = QAction(MainWindow)
-        self.menu_save_as.setObjectName("menu_save_as")
+        self.menu_save_as = QtGui.QAction(parent=MainWindow)
         self.menu_save_as.setEnabled(False)
-        icon5 = QIcon()
-        iconThemeName = "document-save-as"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon5 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon5.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_save_as.setIcon(icon5)
-        self.menu_exit_dialog = QAction(MainWindow)
-        self.menu_exit_dialog.setObjectName("menu_exit_dialog")
+        icon = QtGui.QIcon.fromTheme("document-save-as")
+        self.menu_save_as.setIcon(icon)
+        self.menu_save_as.setObjectName("menu_save_as")
+        self.menu_exit_dialog = QtGui.QAction(parent=MainWindow)
         self.menu_exit_dialog.setCheckable(True)
         self.menu_exit_dialog.setChecked(True)
-        icon6 = QIcon()
-        iconThemeName = "view-close"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon6 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon6.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_exit_dialog.setIcon(icon6)
-        self.menu_close_schedule = QAction(MainWindow)
-        self.menu_close_schedule.setObjectName("menu_close_schedule")
+        icon = QtGui.QIcon.fromTheme("view-close")
+        self.menu_exit_dialog.setIcon(icon)
+        self.menu_exit_dialog.setObjectName("menu_exit_dialog")
+        self.menu_close_schedule = QtGui.QAction(parent=MainWindow)
         self.menu_close_schedule.setEnabled(False)
-        self.menu_close_schedule.setIcon(icon6)
-        self.actionAbout = QAction(MainWindow)
+        icon = QtGui.QIcon.fromTheme("view-close")
+        self.menu_close_schedule.setIcon(icon)
+        self.menu_close_schedule.setObjectName("menu_close_schedule")
+        self.actionAbout = QtGui.QAction(parent=MainWindow)
         self.actionAbout.setObjectName("actionAbout")
-        self.actionDocumentation = QAction(MainWindow)
+        self.actionDocumentation = QtGui.QAction(parent=MainWindow)
         self.actionDocumentation.setObjectName("actionDocumentation")
-        self.actionReorder = QAction(MainWindow)
+        self.actionReorder = QtGui.QAction(parent=MainWindow)
         self.actionReorder.setObjectName("actionReorder")
-        self.actionPlot_schedule = QAction(MainWindow)
+        self.actionPlot_schedule = QtGui.QAction(parent=MainWindow)
         self.actionPlot_schedule.setObjectName("actionPlot_schedule")
-        self.action_view_variables = QAction(MainWindow)
-        self.action_view_variables.setObjectName("action_view_variables")
+        self.action_view_variables = QtGui.QAction(parent=MainWindow)
         self.action_view_variables.setEnabled(False)
-        self.action_view_port_accesses = QAction(MainWindow)
-        self.action_view_port_accesses.setObjectName("action_view_port_accesses")
+        self.action_view_variables.setObjectName("action_view_variables")
+        self.action_view_port_accesses = QtGui.QAction(parent=MainWindow)
         self.action_view_port_accesses.setEnabled(False)
-        self.actionUndo = QAction(MainWindow)
-        self.actionUndo.setObjectName("actionUndo")
+        self.action_view_port_accesses.setObjectName("action_view_port_accesses")
+        self.actionUndo = QtGui.QAction(parent=MainWindow)
         self.actionUndo.setEnabled(False)
-        self.actionRedo = QAction(MainWindow)
-        self.actionRedo.setObjectName("actionRedo")
+        self.actionUndo.setObjectName("actionUndo")
+        self.actionRedo = QtGui.QAction(parent=MainWindow)
         self.actionRedo.setEnabled(False)
-        self.actionIncrease_time_resolution = QAction(MainWindow)
+        self.actionRedo.setObjectName("actionRedo")
+        self.actionIncrease_time_resolution = QtGui.QAction(parent=MainWindow)
         self.actionIncrease_time_resolution.setObjectName(
             "actionIncrease_time_resolution"
         )
-        self.actionDecrease_time_resolution = QAction(MainWindow)
+        self.actionDecrease_time_resolution = QtGui.QAction(parent=MainWindow)
         self.actionDecrease_time_resolution.setObjectName(
             "actionDecrease_time_resolution"
         )
-        self.actionZoom_to_fit = QAction(MainWindow)
+        self.actionZoom_to_fit = QtGui.QAction(parent=MainWindow)
         self.actionZoom_to_fit.setObjectName("actionZoom_to_fit")
-        self.actionStatus_bar = QAction(MainWindow)
-        self.actionStatus_bar.setObjectName("actionStatus_bar")
+        self.actionStatus_bar = QtGui.QAction(parent=MainWindow)
         self.actionStatus_bar.setCheckable(True)
         self.actionStatus_bar.setChecked(True)
-        self.actionToolbar = QAction(MainWindow)
-        self.actionToolbar.setObjectName("actionToolbar")
+        self.actionStatus_bar.setObjectName("actionStatus_bar")
+        self.actionToolbar = QtGui.QAction(parent=MainWindow)
         self.actionToolbar.setCheckable(True)
         self.actionToolbar.setChecked(True)
-        self.action_show_port_numbers = QAction(MainWindow)
-        self.action_show_port_numbers.setObjectName("action_show_port_numbers")
+        self.actionToolbar.setObjectName("actionToolbar")
+        self.action_show_port_numbers = QtGui.QAction(parent=MainWindow)
         self.action_show_port_numbers.setCheckable(True)
         self.action_show_port_numbers.setChecked(False)
         self.action_show_port_numbers.setIconVisibleInMenu(False)
-        self.action_incorrect_execution_time = QAction(MainWindow)
-        self.action_incorrect_execution_time.setObjectName(
-            "action_incorrect_execution_time"
-        )
+        self.action_show_port_numbers.setObjectName("action_show_port_numbers")
+        self.action_incorrect_execution_time = QtGui.QAction(parent=MainWindow)
         self.action_incorrect_execution_time.setCheckable(True)
         self.action_incorrect_execution_time.setChecked(True)
         self.action_incorrect_execution_time.setIconVisibleInMenu(False)
-        self.menu_open = QAction(MainWindow)
+        self.action_incorrect_execution_time.setObjectName(
+            "action_incorrect_execution_time"
+        )
+        self.menu_open = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("personal")
+        self.menu_open.setIcon(icon)
         self.menu_open.setObjectName("menu_open")
-        icon7 = QIcon(QIcon.fromTheme("personal"))
-        self.menu_open.setIcon(icon7)
-        self.actionToggle_full_screen = QAction(MainWindow)
-        self.actionToggle_full_screen.setObjectName("actionToggle_full_screen")
+        self.actionToggle_full_screen = QtGui.QAction(parent=MainWindow)
         self.actionToggle_full_screen.setCheckable(True)
-        self.actionPreferences = QAction(MainWindow)
+        self.actionToggle_full_screen.setObjectName("actionToggle_full_screen")
+        self.actionPreferences = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("preferences-desktop-personal")
+        self.actionPreferences.setIcon(icon)
         self.actionPreferences.setObjectName("actionPreferences")
-        icon8 = QIcon(QIcon.fromTheme("preferences-desktop-personal"))
-        self.actionPreferences.setIcon(icon8)
-        self.centralwidget = QWidget(MainWindow)
-        self.centralwidget.setObjectName("centralwidget")
-        sizePolicy.setHeightForWidth(
-            self.centralwidget.sizePolicy().hasHeightForWidth()
-        )
-        self.centralwidget.setSizePolicy(sizePolicy)
-        self.horizontalLayout = QHBoxLayout(self.centralwidget)
-        self.horizontalLayout.setSpacing(0)
-        self.horizontalLayout.setObjectName("horizontalLayout")
-        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
-        self.splitter = QSplitter(self.centralwidget)
-        self.splitter.setObjectName("splitter")
-        self.splitter.setOrientation(Qt.Horizontal)
-        self.splitter.setHandleWidth(0)
-        self.view = QGraphicsView(self.splitter)
-        self.view.setObjectName("view")
-        self.view.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignTop)
-        self.view.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
-        self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
-        self.splitter.addWidget(self.view)
-        self.info_table = QTableWidget(self.splitter)
-        if self.info_table.columnCount() < 2:
-            self.info_table.setColumnCount(2)
-        font = QFont()
-        font.setBold(False)
-        font.setWeight(50)
-        __qtablewidgetitem = QTableWidgetItem()
-        __qtablewidgetitem.setTextAlignment(Qt.AlignLeading | Qt.AlignVCenter)
-        __qtablewidgetitem.setFont(font)
-        self.info_table.setHorizontalHeaderItem(0, __qtablewidgetitem)
-        __qtablewidgetitem1 = QTableWidgetItem()
-        __qtablewidgetitem1.setTextAlignment(Qt.AlignLeading | Qt.AlignVCenter)
-        self.info_table.setHorizontalHeaderItem(1, __qtablewidgetitem1)
-        if self.info_table.rowCount() < 2:
-            self.info_table.setRowCount(2)
-        __qtablewidgetitem2 = QTableWidgetItem()
-        self.info_table.setVerticalHeaderItem(0, __qtablewidgetitem2)
-        __qtablewidgetitem3 = QTableWidgetItem()
-        self.info_table.setVerticalHeaderItem(1, __qtablewidgetitem3)
-        brush = QBrush(QColor(255, 255, 255, 255))
-        brush.setStyle(Qt.SolidPattern)
-        brush1 = QBrush(QColor(160, 160, 164, 255))
-        brush1.setStyle(Qt.SolidPattern)
-        font1 = QFont()
-        font1.setBold(False)
-        font1.setWeight(50)
-        font1.setKerning(True)
-        __qtablewidgetitem4 = QTableWidgetItem()
-        __qtablewidgetitem4.setFont(font1)
-        __qtablewidgetitem4.setBackground(brush1)
-        __qtablewidgetitem4.setForeground(brush)
-        __qtablewidgetitem4.setFlags(
-            Qt.ItemIsSelectable
-            | Qt.ItemIsEditable
-            | Qt.ItemIsDragEnabled
-            | Qt.ItemIsDropEnabled
-            | Qt.ItemIsUserCheckable
-        )
-        self.info_table.setItem(0, 0, __qtablewidgetitem4)
-        __qtablewidgetitem5 = QTableWidgetItem()
-        __qtablewidgetitem5.setFont(font)
-        __qtablewidgetitem5.setBackground(brush1)
-        __qtablewidgetitem5.setForeground(brush)
-        __qtablewidgetitem5.setFlags(
-            Qt.ItemIsSelectable
-            | Qt.ItemIsEditable
-            | Qt.ItemIsDragEnabled
-            | Qt.ItemIsDropEnabled
-            | Qt.ItemIsUserCheckable
-        )
-        self.info_table.setItem(1, 0, __qtablewidgetitem5)
-        self.info_table.setObjectName("info_table")
-        self.info_table.setStyleSheet(
-            "alternate-background-color: #fadefb;background-color: #ebebeb;"
-        )
-        self.info_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
-        self.info_table.setAlternatingRowColors(True)
-        self.info_table.setSelectionBehavior(QAbstractItemView.SelectRows)
-        self.info_table.setRowCount(2)
-        self.info_table.setColumnCount(2)
-        self.splitter.addWidget(self.info_table)
-        self.info_table.horizontalHeader().setHighlightSections(False)
-        self.info_table.horizontalHeader().setStretchLastSection(True)
-        self.info_table.verticalHeader().setVisible(False)
-        self.info_table.verticalHeader().setDefaultSectionSize(24)
-
-        self.horizontalLayout.addWidget(self.splitter)
-
-        MainWindow.setCentralWidget(self.centralwidget)
-        self.menubar = QMenuBar(MainWindow)
-        self.menubar.setObjectName("menubar")
-        self.menubar.setGeometry(QRect(0, 0, 800, 20))
-        self.menuFile = QMenu(self.menubar)
-        self.menuFile.setObjectName("menuFile")
-        self.menu_Recent_Schedule = QMenu(self.menuFile)
-        self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule")
-        self.menuView = QMenu(self.menubar)
-        self.menuView.setObjectName("menuView")
-        self.menu_view_execution_times = QMenu(self.menuView)
-        self.menu_view_execution_times.setObjectName("menu_view_execution_times")
-        self.menu_view_execution_times.setEnabled(False)
-        self.menu_Edit = QMenu(self.menubar)
-        self.menu_Edit.setObjectName("menu_Edit")
-        self.menuWindow = QMenu(self.menubar)
-        self.menuWindow.setObjectName("menuWindow")
-        self.menuHelp = QMenu(self.menubar)
-        self.menuHelp.setObjectName("menuHelp")
-        MainWindow.setMenuBar(self.menubar)
-        self.statusbar = QStatusBar(MainWindow)
-        self.statusbar.setObjectName("statusbar")
-        MainWindow.setStatusBar(self.statusbar)
-        self.toolBar = QToolBar(MainWindow)
-        self.toolBar.setObjectName("toolBar")
-        MainWindow.addToolBar(Qt.TopToolBarArea, self.toolBar)
-
-        self.menubar.addAction(self.menuFile.menuAction())
-        self.menubar.addAction(self.menu_Edit.menuAction())
-        self.menubar.addAction(self.menuView.menuAction())
-        self.menubar.addAction(self.menuWindow.menuAction())
-        self.menubar.addAction(self.menuHelp.menuAction())
         self.menuFile.addAction(self.menu_open)
         self.menuFile.addAction(self.menu_Recent_Schedule.menuAction())
         self.menuFile.addAction(self.menu_load_from_file)
@@ -322,6 +306,11 @@ class Ui_MainWindow:
         self.menuHelp.addAction(self.actionDocumentation)
         self.menuHelp.addSeparator()
         self.menuHelp.addAction(self.actionAbout)
+        self.menubar.addAction(self.menuFile.menuAction())
+        self.menubar.addAction(self.menu_Edit.menuAction())
+        self.menubar.addAction(self.menuView.menuAction())
+        self.menubar.addAction(self.menuWindow.menuAction())
+        self.menubar.addAction(self.menuHelp.menuAction())
         self.toolBar.addAction(self.menu_open)
         self.toolBar.addAction(self.menu_save)
         self.toolBar.addAction(self.menu_save_as)
@@ -335,300 +324,127 @@ class Ui_MainWindow:
         self.toolBar.addAction(self.actionReorder)
 
         self.retranslateUi(MainWindow)
-
-        QMetaObject.connectSlotsByName(MainWindow)
-
-    # setupUi
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
     def retranslateUi(self, MainWindow):
+        _translate = QtCore.QCoreApplication.translate
+        item = self.info_table.verticalHeaderItem(0)
+        item.setText(_translate("MainWindow", "1"))
+        item = self.info_table.verticalHeaderItem(1)
+        item.setText(_translate("MainWindow", "2"))
+        item = self.info_table.horizontalHeaderItem(0)
+        item.setText(_translate("MainWindow", "Property"))
+        item = self.info_table.horizontalHeaderItem(1)
+        item.setText(_translate("MainWindow", "Value"))
+        __sortingEnabled = self.info_table.isSortingEnabled()
+        self.info_table.setSortingEnabled(False)
+        item = self.info_table.item(0, 0)
+        item.setText(_translate("MainWindow", "Schedule"))
+        item = self.info_table.item(1, 0)
+        item.setText(_translate("MainWindow", "Operator"))
+        self.info_table.setSortingEnabled(__sortingEnabled)
+        self.menuFile.setTitle(_translate("MainWindow", "&File"))
+        self.menu_Recent_Schedule.setTitle(_translate("MainWindow", "Open &recent"))
+        self.menuView.setTitle(_translate("MainWindow", "&View"))
+        self.menu_view_execution_times.setTitle(
+            _translate("MainWindow", "View execution times of type")
+        )
+        self.menu_Edit.setTitle(_translate("MainWindow", "&Edit"))
+        self.menuWindow.setTitle(_translate("MainWindow", "&Window"))
+        self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
+        self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
         self.menu_load_from_file.setText(
-            QCoreApplication.translate(
-                "MainWindow", "&Import schedule from file...", None
-            )
+            _translate("MainWindow", "&Import schedule from file...")
         )
-        # if QT_CONFIG(tooltip)
         self.menu_load_from_file.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Import schedule from python script", None
-            )
+            _translate("MainWindow", "Import schedule from python script")
         )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(statustip)
-        self.menu_load_from_file.setStatusTip("")
-        # endif // QT_CONFIG(statustip)
-        # if QT_CONFIG(shortcut)
-        self.menu_load_from_file.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+I", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_save.setText(QCoreApplication.translate("MainWindow", "&Save", None))
-        # if QT_CONFIG(tooltip)
-        self.menu_save.setToolTip(
-            QCoreApplication.translate("MainWindow", "Save schedule", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_save.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+S", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_node_info.setText(
-            QCoreApplication.translate("MainWindow", "&Node info", None)
-        )
-        # if QT_CONFIG(tooltip)
+        self.menu_load_from_file.setShortcut(_translate("MainWindow", "Ctrl+I"))
+        self.menu_save.setText(_translate("MainWindow", "&Save"))
+        self.menu_save.setToolTip(_translate("MainWindow", "Save schedule"))
+        self.menu_save.setShortcut(_translate("MainWindow", "Ctrl+S"))
+        self.menu_node_info.setText(_translate("MainWindow", "&Node info"))
         self.menu_node_info.setToolTip(
-            QCoreApplication.translate("MainWindow", "Show/hide node information", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_node_info.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+N", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_quit.setText(QCoreApplication.translate("MainWindow", "&Quit", None))
-        # if QT_CONFIG(shortcut)
-        self.menu_quit.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Q", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_save_as.setText(
-            QCoreApplication.translate("MainWindow", "Save &as...", None)
+            _translate("MainWindow", "Show/hide node information")
         )
-        # if QT_CONFIG(tooltip)
+        self.menu_node_info.setShortcut(_translate("MainWindow", "Ctrl+N"))
+        self.menu_quit.setText(_translate("MainWindow", "&Quit"))
+        self.menu_quit.setShortcut(_translate("MainWindow", "Ctrl+Q"))
+        self.menu_save_as.setText(_translate("MainWindow", "Save &as..."))
         self.menu_save_as.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Save schedule with new file name", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_save_as.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Shift+S", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_exit_dialog.setText(
-            QCoreApplication.translate("MainWindow", "&Hide exit dialog", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.menu_exit_dialog.setToolTip(
-            QCoreApplication.translate("MainWindow", "Hide exit dialog", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.menu_close_schedule.setText(
-            QCoreApplication.translate("MainWindow", "&Close schedule", None)
-        )
-        # if QT_CONFIG(shortcut)
-        self.menu_close_schedule.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+W", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionAbout.setText(
-            QCoreApplication.translate("MainWindow", "&About", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionAbout.setToolTip(
-            QCoreApplication.translate("MainWindow", "Open about window", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionDocumentation.setText(
-            QCoreApplication.translate("MainWindow", "&Documentation", None)
-        )
-        # if QT_CONFIG(tooltip)
+            _translate("MainWindow", "Save schedule with new file name")
+        )
+        self.menu_save_as.setShortcut(_translate("MainWindow", "Ctrl+Shift+S"))
+        self.menu_exit_dialog.setText(_translate("MainWindow", "&Hide exit dialog"))
+        self.menu_exit_dialog.setToolTip(_translate("MainWindow", "Hide exit dialog"))
+        self.menu_close_schedule.setText(_translate("MainWindow", "&Close schedule"))
+        self.menu_close_schedule.setShortcut(_translate("MainWindow", "Ctrl+W"))
+        self.actionAbout.setText(_translate("MainWindow", "&About"))
+        self.actionAbout.setToolTip(_translate("MainWindow", "Open about window"))
+        self.actionDocumentation.setText(_translate("MainWindow", "&Documentation"))
         self.actionDocumentation.setToolTip(
-            QCoreApplication.translate("MainWindow", "Open documentation", None)
+            _translate("MainWindow", "Open documentation")
         )
-        # endif // QT_CONFIG(tooltip)
-        self.actionReorder.setText(
-            QCoreApplication.translate("MainWindow", "Reorder", None)
-        )
-        # if QT_CONFIG(tooltip)
+        self.actionReorder.setText(_translate("MainWindow", "Reorder"))
         self.actionReorder.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Reorder schedule based on start time", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.actionReorder.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+R", None)
+            _translate("MainWindow", "Reorder schedule based on start time")
         )
-        # endif // QT_CONFIG(shortcut)
-        self.actionPlot_schedule.setText(
-            QCoreApplication.translate("MainWindow", "&Plot schedule", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionPlot_schedule.setToolTip(
-            QCoreApplication.translate("MainWindow", "Plot schedule", None)
-        )
-        # endif // QT_CONFIG(tooltip)
+        self.actionReorder.setShortcut(_translate("MainWindow", "Ctrl+R"))
+        self.actionPlot_schedule.setText(_translate("MainWindow", "&Plot schedule"))
+        self.actionPlot_schedule.setToolTip(_translate("MainWindow", "Plot schedule"))
         self.action_view_variables.setText(
-            QCoreApplication.translate(
-                "MainWindow", "View execution times of variables", None
-            )
+            _translate("MainWindow", "View execution times of variables")
         )
-        # if QT_CONFIG(tooltip)
         self.action_view_variables.setToolTip(
-            QCoreApplication.translate("MainWindow", "View all variables", None)
+            _translate("MainWindow", "View all variables")
         )
-        # endif // QT_CONFIG(tooltip)
         self.action_view_port_accesses.setText(
-            QCoreApplication.translate(
-                "MainWindow", "View port access statistics", None
-            )
+            _translate("MainWindow", "View port access statistics")
         )
-        # if QT_CONFIG(tooltip)
         self.action_view_port_accesses.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "View port access statistics for storage", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionUndo.setText(QCoreApplication.translate("MainWindow", "Undo", None))
-        # if QT_CONFIG(shortcut)
-        self.actionUndo.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Z", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionRedo.setText(QCoreApplication.translate("MainWindow", "Redo", None))
-        # if QT_CONFIG(shortcut)
-        self.actionRedo.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z", None)
+            _translate("MainWindow", "View port access statistics for storage")
         )
-        # endif // QT_CONFIG(shortcut)
+        self.actionUndo.setText(_translate("MainWindow", "Undo"))
+        self.actionUndo.setShortcut(_translate("MainWindow", "Ctrl+Z"))
+        self.actionRedo.setText(_translate("MainWindow", "Redo"))
+        self.actionRedo.setShortcut(_translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z"))
         self.actionIncrease_time_resolution.setText(
-            QCoreApplication.translate(
-                "MainWindow", "Increase time resolution...", None
-            )
+            _translate("MainWindow", "Increase time resolution...")
         )
         self.actionDecrease_time_resolution.setText(
-            QCoreApplication.translate(
-                "MainWindow", "Decrease time resolution...", None
-            )
-        )
-        self.actionZoom_to_fit.setText(
-            QCoreApplication.translate("MainWindow", "Zoom to &fit", None)
+            _translate("MainWindow", "Decrease time resolution...")
         )
-        self.actionStatus_bar.setText(
-            QCoreApplication.translate("MainWindow", "&Status bar", None)
-        )
-        # if QT_CONFIG(tooltip)
+        self.actionZoom_to_fit.setText(_translate("MainWindow", "Zoom to &fit"))
+        self.actionStatus_bar.setText(_translate("MainWindow", "&Status bar"))
         self.actionStatus_bar.setToolTip(
-            QCoreApplication.translate("MainWindow", "Show/hide status bar", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionToolbar.setText(
-            QCoreApplication.translate("MainWindow", "&Toolbar", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionToolbar.setToolTip(
-            QCoreApplication.translate("MainWindow", "Show/hide toolbar", None)
+            _translate("MainWindow", "Show/hide status bar")
         )
-        # endif // QT_CONFIG(tooltip)
+        self.actionToolbar.setText(_translate("MainWindow", "&Toolbar"))
+        self.actionToolbar.setToolTip(_translate("MainWindow", "Show/hide toolbar"))
         self.action_show_port_numbers.setText(
-            QCoreApplication.translate("MainWindow", "S&how port numbers", None)
+            _translate("MainWindow", "S&how port numbers")
         )
-        # if QT_CONFIG(tooltip)
         self.action_show_port_numbers.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Show port numbers of operation", None
-            )
+            _translate("MainWindow", "Show port numbers of operation")
         )
-        # endif // QT_CONFIG(tooltip)
         self.action_incorrect_execution_time.setText(
-            QCoreApplication.translate("MainWindow", "&Incorrect execution time", None)
+            _translate("MainWindow", "&Incorrect execution time")
         )
-        # if QT_CONFIG(tooltip)
         self.action_incorrect_execution_time.setToolTip(
-            QCoreApplication.translate(
+            _translate(
                 "MainWindow",
                 "Highlight processes with execution time longer than schedule time",
-                None,
             )
         )
-        # endif // QT_CONFIG(tooltip)
-        self.menu_open.setText(
-            QCoreApplication.translate("MainWindow", "&Open...", None)
-        )
-        # if QT_CONFIG(tooltip)
+        self.menu_open.setText(_translate("MainWindow", "&Open..."))
         self.menu_open.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Open previously saved schedule", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_open.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+O", None)
+            _translate("MainWindow", "Open previously saved schedule")
         )
-        # endif // QT_CONFIG(shortcut)
+        self.menu_open.setShortcut(_translate("MainWindow", "Ctrl+O"))
         self.actionToggle_full_screen.setText(
-            QCoreApplication.translate("MainWindow", "Toggle f&ull screen", None)
-        )
-        # if QT_CONFIG(shortcut)
-        self.actionToggle_full_screen.setShortcut(
-            QCoreApplication.translate("MainWindow", "F11", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionPreferences.setText(
-            QCoreApplication.translate("MainWindow", "Preferences", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionPreferences.setToolTip(
-            QCoreApplication.translate("MainWindow", "Color and Fonts", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.actionPreferences.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+M", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        ___qtablewidgetitem = self.info_table.horizontalHeaderItem(0)
-        ___qtablewidgetitem.setText(
-            QCoreApplication.translate("MainWindow", "Property", None)
-        )
-        ___qtablewidgetitem1 = self.info_table.horizontalHeaderItem(1)
-        ___qtablewidgetitem1.setText(
-            QCoreApplication.translate("MainWindow", "Value", None)
-        )
-        ___qtablewidgetitem2 = self.info_table.verticalHeaderItem(0)
-        ___qtablewidgetitem2.setText(
-            QCoreApplication.translate("MainWindow", "1", None)
-        )
-        ___qtablewidgetitem3 = self.info_table.verticalHeaderItem(1)
-        ___qtablewidgetitem3.setText(
-            QCoreApplication.translate("MainWindow", "2", None)
-        )
-
-        __sortingEnabled = self.info_table.isSortingEnabled()
-        self.info_table.setSortingEnabled(False)
-        ___qtablewidgetitem4 = self.info_table.item(0, 0)
-        ___qtablewidgetitem4.setText(
-            QCoreApplication.translate("MainWindow", "Schedule", None)
-        )
-        ___qtablewidgetitem5 = self.info_table.item(1, 0)
-        ___qtablewidgetitem5.setText(
-            QCoreApplication.translate("MainWindow", "Operator", None)
-        )
-        self.info_table.setSortingEnabled(__sortingEnabled)
-
-        self.menuFile.setTitle(QCoreApplication.translate("MainWindow", "&File", None))
-        self.menu_Recent_Schedule.setTitle(
-            QCoreApplication.translate("MainWindow", "Open &recent", None)
+            _translate("MainWindow", "Toggle f&ull screen")
         )
-        self.menuView.setTitle(QCoreApplication.translate("MainWindow", "&View", None))
-        self.menu_view_execution_times.setTitle(
-            QCoreApplication.translate(
-                "MainWindow", "View execution times of type", None
-            )
-        )
-        self.menu_Edit.setTitle(QCoreApplication.translate("MainWindow", "&Edit", None))
-        self.menuWindow.setTitle(
-            QCoreApplication.translate("MainWindow", "&Window", None)
-        )
-        self.menuHelp.setTitle(QCoreApplication.translate("MainWindow", "&Help", None))
-        self.toolBar.setWindowTitle(
-            QCoreApplication.translate("MainWindow", "toolBar", None)
-        )
-        pass
-
-    # retranslateUi
+        self.actionToggle_full_screen.setShortcut(_translate("MainWindow", "F11"))
+        self.actionPreferences.setText(_translate("MainWindow", "Preferences"))
+        self.actionPreferences.setToolTip(_translate("MainWindow", "Color and Fonts"))
+        self.actionPreferences.setShortcut(_translate("MainWindow", "Ctrl+M"))
diff --git a/pyproject.toml b/pyproject.toml
index c0d7de2f..a9074708 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ description = "Better ASIC Toolbox"
 readme = "README.md"
 maintainers = [{ name = "Oscar Gustafsson", email = "oscar.gustafsson@liu.se" }]
 license = { file = "LICENSE" }
-requires-python = ">=3.8"
+requires-python = ">=3.10"
 dependencies = [
   "numpy",
   "qtpy",
@@ -12,16 +12,16 @@ dependencies = [
   "matplotlib>=3.7",
   "setuptools_scm[toml]>=6.2",
   "networkx>=3",
-  "qtawesome"
+  "qtawesome",
 ]
 classifiers = [
   "Intended Audience :: Education",
   "Intended Audience :: Science/Research",
   "Programming Language :: Python :: 3",
-  "Programming Language :: Python :: 3.8",
-  "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
+  "Programming Language :: Python :: 3.13",
   "Programming Language :: C++",
   "License :: OSI Approved :: MIT License",
   "Operating System :: OS Independent",
-- 
GitLab