Add global delay settings for steps in Scenario and MainWindow
This commit is contained in:
@@ -659,7 +659,9 @@ class Scenario:
|
|||||||
# Global delay settings - delays in milliseconds
|
# Global delay settings - delays in milliseconds
|
||||||
self.global_delay = global_delay or {
|
self.global_delay = global_delay or {
|
||||||
'before_action': 0, # Delay before each action in ms
|
'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):
|
def to_dict(self):
|
||||||
@@ -680,7 +682,9 @@ class Scenario:
|
|||||||
# Handle backward compatibility for scenarios without global_delay
|
# Handle backward compatibility for scenarios without global_delay
|
||||||
global_delay = data.get('global_delay', {
|
global_delay = data.get('global_delay', {
|
||||||
'before_action': 0,
|
'before_action': 0,
|
||||||
'after_action': 0
|
'after_action': 0,
|
||||||
|
'before_step': 0,
|
||||||
|
'after_step': 0
|
||||||
})
|
})
|
||||||
return Scenario(data['name'], data.get('steps', []), global_delay)
|
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}')
|
self.set_state(f'Performing step: {step_name}')
|
||||||
logger.info(f"Executing 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
|
# Execute step actions
|
||||||
success = self._execute_step_actions(step, detections)
|
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:
|
if success:
|
||||||
self._step_cooldown[step_name] = current_time
|
self._step_cooldown[step_name] = current_time
|
||||||
step_executed = True
|
step_executed = True
|
||||||
@@ -3078,39 +3096,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.combo.currentIndexChanged.connect(self._log_combo_scenario)
|
self.combo.currentIndexChanged.connect(self._log_combo_scenario)
|
||||||
scenario_group_layout.addWidget(self.combo)
|
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
|
# Window selection dropdown
|
||||||
self.window_combo = QtWidgets.QComboBox()
|
self.window_combo = QtWidgets.QComboBox()
|
||||||
self.window_combo.setMinimumWidth(90)
|
self.window_combo.setMinimumWidth(90)
|
||||||
@@ -3123,8 +3108,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.btn_refresh_windows = QtWidgets.QPushButton('Refresh')
|
self.btn_refresh_windows = QtWidgets.QPushButton('Refresh')
|
||||||
self.btn_refresh_windows.setToolTip('Refresh open windows list')
|
self.btn_refresh_windows.setToolTip('Refresh open windows list')
|
||||||
self.btn_refresh_windows.clicked.connect(self._log_btn_refresh_windows)
|
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)
|
window_group_box.setLayout(window_group_layout)
|
||||||
self.refresh_window_list()
|
self.refresh_window_list()
|
||||||
# Scenario actions
|
# Scenario actions
|
||||||
@@ -3201,6 +3189,67 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
steps_group_layout.addLayout(step_btn_group_layout)
|
steps_group_layout.addLayout(step_btn_group_layout)
|
||||||
steps_group_box.setLayout(steps_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
|
# Start/Stop Combined
|
||||||
self.btn_start_stop = QtWidgets.QPushButton(f'Start ({self.hotkey.upper()})')
|
self.btn_start_stop = QtWidgets.QPushButton(f'Start ({self.hotkey.upper()})')
|
||||||
self.btn_start_stop.setMinimumWidth(80)
|
self.btn_start_stop.setMinimumWidth(80)
|
||||||
@@ -3253,7 +3302,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
layout.addWidget(scenario_group_box, 0, 0, 1, 5)
|
layout.addWidget(scenario_group_box, 0, 0, 1, 5)
|
||||||
layout.setRowStretch(0, 0) # Scenario group should not stretch vertically
|
layout.setRowStretch(0, 0) # Scenario group should not stretch vertically
|
||||||
layout.addWidget(window_group_box, 1, 0, 1, 5)
|
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
|
# Resource usage group
|
||||||
layout.addWidget(self.resource_group, 5, 0, 1, 5)
|
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.
|
Handle changes to global delay settings and auto-save scenario.
|
||||||
"""
|
"""
|
||||||
if self.current_scenario:
|
if self.current_scenario:
|
||||||
before_delay = self.before_action_spinbox.value()
|
before_action_delay = self.before_action_spinbox.value()
|
||||||
after_delay = self.after_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 = {
|
self.current_scenario.global_delay = {
|
||||||
'before_action': before_delay,
|
'before_action': before_action_delay,
|
||||||
'after_action': after_delay
|
'after_action': after_action_delay,
|
||||||
|
'before_step': before_step_delay,
|
||||||
|
'after_step': after_step_delay
|
||||||
}
|
}
|
||||||
|
|
||||||
# Auto-save the scenario with new delay settings
|
# Auto-save the scenario with new delay settings
|
||||||
self.current_scenario.save()
|
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):
|
def _log_combo_window(self, idx):
|
||||||
"""
|
"""
|
||||||
@@ -4074,23 +4133,35 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
# Temporarily disconnect signals to prevent triggering auto-save during loading
|
# Temporarily disconnect signals to prevent triggering auto-save during loading
|
||||||
self.before_action_spinbox.valueChanged.disconnect()
|
self.before_action_spinbox.valueChanged.disconnect()
|
||||||
self.after_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
|
# Load global delay settings
|
||||||
global_delay = self.current_scenario.global_delay
|
global_delay = self.current_scenario.global_delay
|
||||||
self.before_action_spinbox.setValue(global_delay.get('before_action', 0))
|
self.before_action_spinbox.setValue(global_delay.get('before_action', 0))
|
||||||
self.after_action_spinbox.setValue(global_delay.get('after_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
|
# Reconnect signals
|
||||||
self.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed)
|
self.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed)
|
||||||
self.after_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:
|
else:
|
||||||
# Reset to default values when no scenario is selected
|
# Reset to default values when no scenario is selected
|
||||||
self.before_action_spinbox.valueChanged.disconnect()
|
self.before_action_spinbox.valueChanged.disconnect()
|
||||||
self.after_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.before_action_spinbox.setValue(0)
|
||||||
self.after_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.before_action_spinbox.valueChanged.connect(self._on_global_delay_changed)
|
||||||
self.after_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
|
return
|
||||||
|
|
||||||
for step in self.current_scenario.steps:
|
for step in self.current_scenario.steps:
|
||||||
|
|||||||
Reference in New Issue
Block a user