Skip to content

Play/pause update for mini GUI - #290

Open
michaellans wants to merge 31 commits into
xopt-org:mainfrom
michaellans:play_pause_update
Open

michaellans wants to merge 31 commits into
xopt-org:mainfrom
michaellans:play_pause_update

Conversation

@michaellans

@michaellans michaellans commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

This PR features an update to the Badger mini run button behavior and routine subprocess and termination condition control flow, as well as an improvement to the variable range dialog window and a couple bug fixes.

Previously, every time the play button was pressed to start a run, a new routine_runner instance was initialized, which passed args to a new subprocess to run the optimization:


Stopping a routine closed and terminated the subprocess:
def stop_routine(self) -> None:

Updated Run Controls

This PR adds a new run controller class to replace the various run actions in the action bar and handle the logic for pause, resume, stop, and start based on the run_monitor state (is a subprocess active, is the optimization loop paused) and routine_page/env_cbox configuration (has anything changed, and are the current settings compatible with the displayed data).

  • Pressing the play button will pause an actively running routine
  • Pressing play to start an optimization will get a snapshot of the current GUI parameters and run_monitor state, and will resume or restart based on the following logic:
    • If the snapshot is identical to the displayed routine: unpause and continue
    • If parameters have changed but are still compatible with the displayed data: stop the active routine/subprocess, load the displayed data, and create a new routine/start a new subprocess to continue the optimization with the new parameters.
    • If variables or objectives have changed and displayed data is no longer compatible: stop the current routine, and restart a new routine with the selected parameters
  • A new routine will also be restarted (without loading data) if the reset button is pressed, a solution is dialed in, a previous run is selected from the history tab, or a new template is loaded.

Signals between the action_bar, run_controller, home_page, and run_monitor are all connected in the home_page config_logic method.

The run button menu options are updated from ["Run", "Run Until", and "Resume"] to ["New Run" and "Edit Condition"].

  • "New Run" should have the same effect as the old run button start behavior: start a new routine by sampling initial points from the current variable values. However instead of changing the default button action to emit a different signal and call a different start_run method, it sets a flag to override the resume logic in run_controller and start a new run.
  • "Edit Condition" opens a dialog window to edit the termination condition, but does not start a new routine. Instead the dialog allows you to save a new termination condition, which is stored in the run_monitor, as either a dict or None to run until manually stopped.
    • On the 'main' GUI, the "Edit Condition" behavior remains unchanged and will start a new routine.

Handling Termination Conditions

Instead of being part of the start_run logic and enabled by passing a flag, this PR updates how the termination conditions are stored and applied to routines. The configured termination_condition is stored in the run_monitor (BadgerOptMonitor) class. The termination_condition gets passed in the args to each new routine, either as a dictionary with a configured number of iterations, time in seconds, and 'tc_idx' indicating which to use, or as 'None' to continue until manually stopped.

The termination_condition is extended from the current state each time an active routine is unpaused, so the behavior will be consistent as 'each time the play button is pressed, the routine will run for n iterations or n seconds' regardless of whether the optimization is resumed or restarted.

  • This is accomplished by adding a termination_control_queue to the subprocess. When an active but paused subprocess loop is unpaused, it checks this queue for an updated termination condition from the GUI, and either adds the specified number of seconds or iterations to it's current state before resuming, or clears it's condition if given None as the new termination_condition.
  • The current termination_condition (number of iterations to add, or number of seconds to add) is shown on the play button to indicate the next run duration.
  • The termination_condition can be changed by selecting "Edit Condition" from the run button menu

Other changes

  • updated/added new signals for resetting the environment, setting variables, and also pausing a routine so that the GUI updates after the changes are finished rather than when the action is taken
  • Removed the old pause button
  • Updated window close behavior to ensure an active subprocess is stopped and cleaned up during window shutdown
  • Updated ind_lim_vrange_dialog to show the current bounds when opened. I did this to find and fix an issue with initial points and variable bounds, but I could split it into a separate PR since it's separate from the main changes here.

Bug Fixes

  • Enabled loading routine data for neldermead and removed error message when trying to load data with neldermead selected
  • Fixed pre-existing bug which could cause GUI to freeze when closing the application during a paused or running routine.
  • Fixed two bugs with initial points. The first 'current' point is no longer rounded, as that could cause it to be outside the variable bounds in some cases. Also changed when the initial points table is updated when starting a new routine to avoid stale points being passed to the subprocess.
  • Switching from the previous stop behavior to pausing with a confirmation fixes When a run is stopped, the last sampled point is not shown #225, since the loop is paused at a known state which has already been sent back to the GUI

Tests

  • Added tests for the new run controller.
  • Updated pause/play tests for the revised control flow.
  • NOTE: Some tests are still broken from changing the start_run method signature to remove the termination_condition flag, and I haven't had a chance to fix them yet

@MitchellAV MitchellAV left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't able to find any issues during my limited testing in both -g and -mini graphics modes. I pulled in the latest changes from main and should have fixed the failing test (last github action run was hanging for some reason). I made some comments to look at.

Not blocking but...the entire PR does not have any type hints and will be adding more work on my end in #289. While not mandatory as part of the pre-commit hooks for the repo now, it will be in the future so might be worth getting used to when creating methods args and initializing variables.

Comment thread src/badger/gui/components/action_bar.py Outdated
class BadgerActionBar(QWidget):
sig_start = pyqtSignal()
sig_start_until = pyqtSignal(
sig_start_until = pyqtSignal( # I think this is now deprecated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are correct. There is no emit() for this signal any longer with the new rework of the action bar. This would also make def start_run_until() method in the BadgerHomePage class obsolete and should be removed along with it's connection in config_logic() method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed start_run_until and connected signals d149aa8


# TODO: This is quite clunky, the run button (btn_stop) should really have
# its own class with action/signal/ui logic.
if self.mini_mode:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both branches of this case statement should probably be refactored to handle the different display modes better, but it seems like you're aware of that with the separate widget comment. If you could at least separate out the common methods in both branches it would help with the clarity for now. Not blocking.


def closeEvent(self, event):
self.save_config(self.configs)
# self.save_config(self.configs)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove outdated code if no longer necessary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed commented line d149aa8

@michaellans

Copy link
Copy Markdown
Contributor Author

Wasn't able to find any issues during my limited testing in both -g and -mini graphics modes. I pulled in the latest changes from main and should have fixed the failing test (last github action run was hanging for some reason). I made some comments to look at.

Not blocking but...the entire PR does not have any type hints and will be adding more work on my end in #289. While not mandatory as part of the pre-commit hooks for the repo now, it will be in the future so might be worth getting used to when creating methods args and initializing variables.

Thanks for the review, I've made a couple updates to fix the tests that were hanging and remove deprecated code. A lot of this did have type hints but I think I've now added them to all methods whose signatures have changed. Let me know how this looks.

@michaellans
michaellans marked this pull request as ready for review October 2, 2026 19:32

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When a run is stopped, the last sampled point is not shown

2 participants