From 7560474f5be9b8d0f58e61d1626794624858c8d6 Mon Sep 17 00:00:00 2001 From: Gabriel20xx Date: Thu, 7 Aug 2025 13:44:52 +0200 Subject: [PATCH] Add global delay settings for steps in Scenario and MainWindow --- main.py | 157 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 114 insertions(+), 43 deletions(-) diff --git a/main.py b/main.py index 78dc456..049aac9 100644 --- a/main.py +++ b/main.py @@ -659,7 +659,9 @@ class Scenario: # Global delay settings - delays in milliseconds self.global_delay = global_delay or { 'before_action': 0, # Delay before each action in ms - 'after_action': 0 # Delay after each action in ms + 'after_action': 0, # Delay after each action in ms + 'before_step': 0, # Delay before each step in ms + 'after_step': 0 # Delay after each step in ms } def to_dict(self): @@ -680,7 +682,9 @@ class Scenario: # Handle backward compatibility for scenarios without global_delay global_delay = data.get('global_delay', { 'before_action': 0, - 'after_action': 0 + 'after_action': 0, + 'before_step': 0, + 'after_step': 0 }) return Scenario(data['name'], data.get('steps', []), global_delay) @@ -1284,9 +1288,23 @@ class MainWindow(QtWidgets.QMainWindow): self.set_state(f'Performing step: {step_name}') logger.info(f"Executing step: {step_name}") + # Apply global before-step delay + if self.current_scenario and self.current_scenario.global_delay: + before_step_delay = self.current_scenario.global_delay.get('before_step', 0) + if before_step_delay > 0: + logger.debug(f'Applying global before-step delay: {before_step_delay}ms') + time.sleep(before_step_delay / 1000.0) + # Execute step actions success = self._execute_step_actions(step, detections) + # Apply global after-step delay + if self.current_scenario and self.current_scenario.global_delay: + after_step_delay = self.current_scenario.global_delay.get('after_step', 0) + if after_step_delay > 0: + logger.debug(f'Applying global after-step delay: {after_step_delay}ms') + time.sleep(after_step_delay / 1000.0) + if success: self._step_cooldown[step_name] = current_time step_executed = True @@ -3078,39 +3096,6 @@ class MainWindow(QtWidgets.QMainWindow): self.combo.currentIndexChanged.connect(self._log_combo_scenario) scenario_group_layout.addWidget(self.combo) - # Global delay settings - global_delay_layout = QtWidgets.QHBoxLayout() - global_delay_layout.setSpacing(8) - global_delay_layout.setContentsMargins(0, 5, 0, 5) - - # Before action delay - before_label = QtWidgets.QLabel('Before Action (ms):') - before_label.setMinimumWidth(100) - self.before_action_spinbox = QtWidgets.QSpinBox() - self.before_action_spinbox.setRange(0, 10000) - self.before_action_spinbox.setValue(0) - self.before_action_spinbox.setSuffix(' ms') - self.before_action_spinbox.setToolTip('Delay before each action in milliseconds') - self.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed) - - # After action delay - after_label = QtWidgets.QLabel('After Action (ms):') - after_label.setMinimumWidth(95) - self.after_action_spinbox = QtWidgets.QSpinBox() - self.after_action_spinbox.setRange(0, 10000) - self.after_action_spinbox.setValue(0) - self.after_action_spinbox.setSuffix(' ms') - self.after_action_spinbox.setToolTip('Delay after each action in milliseconds') - self.after_action_spinbox.valueChanged.connect(self._on_global_delay_changed) - - global_delay_layout.addWidget(before_label) - global_delay_layout.addWidget(self.before_action_spinbox) - global_delay_layout.addWidget(after_label) - global_delay_layout.addWidget(self.after_action_spinbox) - global_delay_layout.addStretch() - - scenario_group_layout.addLayout(global_delay_layout) - # Window selection dropdown self.window_combo = QtWidgets.QComboBox() self.window_combo.setMinimumWidth(90) @@ -3123,8 +3108,11 @@ class MainWindow(QtWidgets.QMainWindow): self.btn_refresh_windows = QtWidgets.QPushButton('Refresh') self.btn_refresh_windows.setToolTip('Refresh open windows list') self.btn_refresh_windows.clicked.connect(self._log_btn_refresh_windows) - window_group_layout.addWidget(self.window_combo) - window_group_layout.addWidget(self.btn_refresh_windows) + + # Add widgets with stretch factors: combo gets 3/4, refresh button gets 1/4 + window_group_layout.addWidget(self.window_combo, 3) # 3/4 of the width + window_group_layout.addWidget(self.btn_refresh_windows, 1) # 1/4 of the width + window_group_box.setLayout(window_group_layout) self.refresh_window_list() # Scenario actions @@ -3201,6 +3189,67 @@ class MainWindow(QtWidgets.QMainWindow): steps_group_layout.addLayout(step_btn_group_layout) steps_group_box.setLayout(steps_group_layout) + # Global Delay Settings group + global_delay_group_box = QtWidgets.QGroupBox('Global Delay Settings (ms)') + global_delay_group_box.setSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed) + global_delay_group_layout = QtWidgets.QGridLayout() + global_delay_group_layout.setSpacing(8) + global_delay_group_layout.setContentsMargins(8, 8, 8, 8) + + # Action delays (top row) + action_label = QtWidgets.QLabel('Action Delays:') + action_label.setStyleSheet('font-weight: bold;') + global_delay_group_layout.addWidget(action_label, 0, 0, 1, 4) + + before_action_label = QtWidgets.QLabel('Before Action:') + self.before_action_spinbox = QtWidgets.QSpinBox() + self.before_action_spinbox.setRange(0, 10000) + self.before_action_spinbox.setValue(0) + self.before_action_spinbox.setSuffix(' ms') + self.before_action_spinbox.setToolTip('Delay before each action in milliseconds') + self.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed) + + after_action_label = QtWidgets.QLabel('After Action:') + self.after_action_spinbox = QtWidgets.QSpinBox() + self.after_action_spinbox.setRange(0, 10000) + self.after_action_spinbox.setValue(0) + self.after_action_spinbox.setSuffix(' ms') + self.after_action_spinbox.setToolTip('Delay after each action in milliseconds') + self.after_action_spinbox.valueChanged.connect(self._on_global_delay_changed) + + global_delay_group_layout.addWidget(before_action_label, 1, 0) + global_delay_group_layout.addWidget(self.before_action_spinbox, 1, 1) + global_delay_group_layout.addWidget(after_action_label, 1, 2) + global_delay_group_layout.addWidget(self.after_action_spinbox, 1, 3) + + # Step delays (bottom row) + step_label = QtWidgets.QLabel('Step Delays:') + step_label.setStyleSheet('font-weight: bold;') + global_delay_group_layout.addWidget(step_label, 2, 0, 1, 4) + + before_step_label = QtWidgets.QLabel('Before Step:') + self.before_step_spinbox = QtWidgets.QSpinBox() + self.before_step_spinbox.setRange(0, 10000) + self.before_step_spinbox.setValue(0) + self.before_step_spinbox.setSuffix(' ms') + self.before_step_spinbox.setToolTip('Delay before each step execution in milliseconds') + self.before_step_spinbox.valueChanged.connect(self._on_global_delay_changed) + + after_step_label = QtWidgets.QLabel('After Step:') + self.after_step_spinbox = QtWidgets.QSpinBox() + self.after_step_spinbox.setRange(0, 10000) + self.after_step_spinbox.setValue(0) + self.after_step_spinbox.setSuffix(' ms') + self.after_step_spinbox.setToolTip('Delay after each step execution in milliseconds') + self.after_step_spinbox.valueChanged.connect(self._on_global_delay_changed) + + global_delay_group_layout.addWidget(before_step_label, 3, 0) + global_delay_group_layout.addWidget(self.before_step_spinbox, 3, 1) + global_delay_group_layout.addWidget(after_step_label, 3, 2) + global_delay_group_layout.addWidget(self.after_step_spinbox, 3, 3) + + global_delay_group_box.setLayout(global_delay_group_layout) + # Start/Stop Combined self.btn_start_stop = QtWidgets.QPushButton(f'Start ({self.hotkey.upper()})') self.btn_start_stop.setMinimumWidth(80) @@ -3253,7 +3302,11 @@ class MainWindow(QtWidgets.QMainWindow): layout.addWidget(scenario_group_box, 0, 0, 1, 5) layout.setRowStretch(0, 0) # Scenario group should not stretch vertically layout.addWidget(window_group_box, 1, 0, 1, 5) - layout.addWidget(steps_group_box, 2, 0, 3, 5) + layout.addWidget(steps_group_box, 2, 0, 2, 5) + + # Global delay group + layout.addWidget(global_delay_group_box, 4, 0, 1, 5) + layout.setRowStretch(4, 0) # Global delay group should not stretch vertically # Resource usage group layout.addWidget(self.resource_group, 5, 0, 1, 5) @@ -3356,17 +3409,23 @@ class MainWindow(QtWidgets.QMainWindow): Handle changes to global delay settings and auto-save scenario. """ if self.current_scenario: - before_delay = self.before_action_spinbox.value() - after_delay = self.after_action_spinbox.value() + before_action_delay = self.before_action_spinbox.value() + after_action_delay = self.after_action_spinbox.value() + before_step_delay = self.before_step_spinbox.value() + after_step_delay = self.after_step_spinbox.value() self.current_scenario.global_delay = { - 'before_action': before_delay, - 'after_action': after_delay + 'before_action': before_action_delay, + 'after_action': after_action_delay, + 'before_step': before_step_delay, + 'after_step': after_step_delay } # Auto-save the scenario with new delay settings self.current_scenario.save() - logger.info(f"Global delay updated: before={before_delay}ms, after={after_delay}ms") + logger.info(f"Global delay updated: before_action={before_action_delay}ms, " + f"after_action={after_action_delay}ms, before_step={before_step_delay}ms, " + f"after_step={after_step_delay}ms") def _log_combo_window(self, idx): """ @@ -4074,23 +4133,35 @@ class MainWindow(QtWidgets.QMainWindow): # Temporarily disconnect signals to prevent triggering auto-save during loading self.before_action_spinbox.valueChanged.disconnect() self.after_action_spinbox.valueChanged.disconnect() + self.before_step_spinbox.valueChanged.disconnect() + self.after_step_spinbox.valueChanged.disconnect() # Load global delay settings global_delay = self.current_scenario.global_delay self.before_action_spinbox.setValue(global_delay.get('before_action', 0)) self.after_action_spinbox.setValue(global_delay.get('after_action', 0)) + self.before_step_spinbox.setValue(global_delay.get('before_step', 0)) + self.after_step_spinbox.setValue(global_delay.get('after_step', 0)) # Reconnect signals self.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed) self.after_action_spinbox.valueChanged.connect(self._on_global_delay_changed) + self.before_step_spinbox.valueChanged.connect(self._on_global_delay_changed) + self.after_step_spinbox.valueChanged.connect(self._on_global_delay_changed) else: # Reset to default values when no scenario is selected self.before_action_spinbox.valueChanged.disconnect() self.after_action_spinbox.valueChanged.disconnect() + self.before_step_spinbox.valueChanged.disconnect() + self.after_step_spinbox.valueChanged.disconnect() self.before_action_spinbox.setValue(0) self.after_action_spinbox.setValue(0) + self.before_step_spinbox.setValue(0) + self.after_step_spinbox.setValue(0) self.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed) self.after_action_spinbox.valueChanged.connect(self._on_global_delay_changed) + self.before_step_spinbox.valueChanged.connect(self._on_global_delay_changed) + self.after_step_spinbox.valueChanged.connect(self._on_global_delay_changed) return for step in self.current_scenario.steps: