diff --git a/src/simudator/gui/gui.py b/src/simudator/gui/gui.py index 7aa2f8118bed5c1906c20c0431eff5b7108e5284..8e2348a1000667f881156678be9716ac2c8b0589 100644 --- a/src/simudator/gui/gui.py +++ b/src/simudator/gui/gui.py @@ -116,6 +116,14 @@ class GUI(QMainWindow): # Signal to tell gui when cpu has halted self.cpu_tick_signal.connect(self.handleCpuTick) + # Used to set if all values in the gui should be updated each tick + # or only the clock counter + self.update_all_values = False + + # Used to set the update delay + # Useful when watching the values being updated while running + self.update_delay = 0.00 + # Used to lock some actions in ui when cpu is running in another thread # Using the cpu's internal status directly could case problems self.cpu_running = False @@ -207,9 +215,22 @@ class GUI(QMainWindow): self.breakpoint_action.setStatusTip("Open breakpoint window.") self.breakpoint_action.triggered.connect(self.openBreakpointWindow) + # Create 'update value' window button + self.update_value_action = QAction("Update values while running", self, checkable=True) + self.update_value_action.setChecked(False) + self.update_value_action.setStatusTip("Toggle value updates while running.") + self.update_value_action.triggered.connect(self.toggle_value_update_on_run) + + # Create 'set delay' window button + self.set_delay_action = QAction("Set update delay", self) + self.set_delay_action.setStatusTip("Sets the delay between each update when the cpu is running.") + self.set_delay_action.triggered.connect(self.set_update_delay) + # Create Tools menu for tool actions actions tools_menu = menu.addMenu("&Tools") tools_menu.addAction(self.breakpoint_action) + tools_menu.addAction(self.update_value_action) + tools_menu.addAction(self.set_delay_action) # Add run button on toolbar arrow_icon = self.style().standardIcon(QStyle.SP_MediaPlay) @@ -434,9 +455,8 @@ class GUI(QMainWindow): self.cpu_running = True self.setDisabledWhenRunning(True) self.cpu.unstop() - simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, False, steps) + simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay, False, steps) self.threadpool.start(simulation_thread) - # self.updateCpuListeners() def runToolBarButtonClick(self) -> None: """ @@ -451,9 +471,8 @@ class GUI(QMainWindow): self.cpu_running = True self.setDisabledWhenRunning(True) self.cpu.unstop() - simulation_thread = RunThread(self.cpu, self.cpu_tick_signal) + simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay) self.threadpool.start(simulation_thread) - self.updateCpuListeners() @Slot(int) def handleCpuTick(self, steps: int) -> None: @@ -465,11 +484,13 @@ class GUI(QMainWindow): # Update cpu clock counter every tick self.updateCpuClockCycle() + if self.update_all_values: + self.updateCpuListeners() + # If a breakpoint halted the program, inform the user # Update other visuals and set the cpu to the correct state (not running) if self.cpu.breakpoint_reached: self.messageBox("Reached breakpoint: " + self.cpu.last_breakpoint.__str__()) - self.updateCpuListeners() # When the CPU is done we want to inform the user and update visuals if self.cpu.should_halt(): @@ -478,7 +499,6 @@ class GUI(QMainWindow): # the message box after every small step if steps > self.HALT_MESSAGE_THRESHOLD: self.messageBox("The processor halted.") - self.updateCpuListeners() # A signal of 0 steps signifies end of execution, i.e. the CPU has # halted or run the specified amount of ticks @@ -486,13 +506,13 @@ class GUI(QMainWindow): if steps == 0: self.cpu_running = False self.setDisabledWhenRunning(False) + self.updateCpuListeners() def stopToolBarButtonClick(self) -> None: """ Tells the cpu to stop. It will then stop at an appropriate in its own thread. """ self.cpu.stop() - self.updateCpuListeners() def folderSaveDialog(self) -> str: """ @@ -757,6 +777,20 @@ class GUI(QMainWindow): self.breakpoint_window = BreakpointWindow(self.cpu) self.breakpoint_window.show() + def toggle_value_update_on_run(self): + """ + Toggles whether all values or only clock cycle is being updated each tick. + """ + self.update_all_values = not self.update_all_values + + def set_update_delay(self): + """ + Sets the update delay for the visual updates while the cpu is running. + """ + delay, ok = QInputDialog.getDouble(self, "Input Dialog", "Enter a float value:", decimals=5) + if ok: + self.update_delay = delay + def showPortNamesBarButtonClick(self): """ Toggles showing port names in the graphics scene. diff --git a/src/simudator/gui/run_continuously_thread.py b/src/simudator/gui/run_continuously_thread.py index e2693fea1c14fba817375b967c04db9f633f9a8d..d615f61ac344002be4ddbb31e9f0062a7f403827 100644 --- a/src/simudator/gui/run_continuously_thread.py +++ b/src/simudator/gui/run_continuously_thread.py @@ -2,8 +2,6 @@ import time from qtpy.QtCore import QRunnable -CPU_TICK_DELAY = 0.0000001 - class RunThread(QRunnable): """ This class is used to run the simulated cpu several ticks or continuously on @@ -15,25 +13,26 @@ class RunThread(QRunnable): has halted. """ - def __init__(self, cpu, signal, run_continuously=True, steps=0): + def __init__(self, cpu, signal, delay: float, run_continuously=True, steps=0): super().__init__() self.cpu = cpu self.signal = signal self.run_continuously = run_continuously self.steps = steps + self.delay = delay def run(self): if self.run_continuously: while not self.cpu.should_halt() and not self.cpu.is_stopped: self.cpu.do_tick() self.signal.emit(1) - time.sleep(CPU_TICK_DELAY) + time.sleep(self.delay) else: for _ in range(self.steps): self.cpu.do_tick() self.signal.emit(1) - time.sleep(CPU_TICK_DELAY) + time.sleep(self.delay) # Signal end of execution as having run 0 ticks self.signal.emit(0)