Refactor automation controls and enhance state management in MainWindow
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
@@ -11,7 +10,6 @@ from PyQt6 import QtWidgets, QtGui, QtCore
|
|||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyautogui
|
import pyautogui
|
||||||
import mss
|
|
||||||
from pynput import keyboard
|
from pynput import keyboard
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from PIL import ImageGrab, Image, ImageTk
|
from PIL import ImageGrab, Image, ImageTk
|
||||||
@@ -135,6 +133,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
logger.info('Automation loop started.')
|
logger.info('Automation loop started.')
|
||||||
try:
|
try:
|
||||||
while self.running:
|
while self.running:
|
||||||
|
# Only update the state label, do not log every loop
|
||||||
|
self.set_state('Looking for matches')
|
||||||
screen = pyautogui.screenshot()
|
screen = pyautogui.screenshot()
|
||||||
screen_np = cv2.cvtColor(np.array(screen), cv2.COLOR_RGB2BGR)
|
screen_np = cv2.cvtColor(np.array(screen), cv2.COLOR_RGB2BGR)
|
||||||
for step in self.current_scenario.steps:
|
for step in self.current_scenario.steps:
|
||||||
@@ -165,6 +165,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
trigger = len(found) > 0
|
trigger = len(found) > 0
|
||||||
logger.debug(f"Step '{step.get('name', 'step')}' trigger check: found={found}, cond={cond}, trigger={trigger}")
|
logger.debug(f"Step '{step.get('name', 'step')}' trigger check: found={found}, cond={cond}, trigger={trigger}")
|
||||||
if trigger:
|
if trigger:
|
||||||
|
self.set_state(f'Performing step: {step.get("name", "step")})')
|
||||||
|
logger.info(f"Found match for step: {step.get('name', 'step')}. Performing actions.")
|
||||||
# Use the first detected image for position
|
# Use the first detected image for position
|
||||||
ref_img = found[0] if found else step.get('images', [])[0]
|
ref_img = found[0] if found else step.get('images', [])[0]
|
||||||
loc, shape = detections.get(ref_img.get('name'), ((0, 0), (0, 0, 0)))
|
loc, shape = detections.get(ref_img.get('name'), ((0, 0), (0, 0, 0)))
|
||||||
@@ -175,6 +177,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Automation loop error: {e}')
|
logger.error(f'Automation loop error: {e}')
|
||||||
|
finally:
|
||||||
|
self.set_state('Paused')
|
||||||
|
|
||||||
def _perform_step_action(self, action, loc, shape):
|
def _perform_step_action(self, action, loc, shape):
|
||||||
act_type = action['type']
|
act_type = action['type']
|
||||||
@@ -215,12 +219,24 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
time.sleep(duration)
|
time.sleep(duration)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Error performing step action {act_type}: {e}')
|
logger.error(f'Error performing step action {act_type}: {e}')
|
||||||
|
def set_state(self, text):
|
||||||
|
self.state_text = text
|
||||||
|
self.state_label.setText(f'State: {text}')
|
||||||
|
|
||||||
|
def toggle_automation(self):
|
||||||
|
if self.running:
|
||||||
|
self.stop_automation()
|
||||||
|
else:
|
||||||
|
self.start_automation()
|
||||||
|
|
||||||
def start_automation(self):
|
def start_automation(self):
|
||||||
logger.info('Starting automation.')
|
logger.info('Starting automation.')
|
||||||
if not self.current_scenario or self.running:
|
if not self.current_scenario or self.running:
|
||||||
logger.warning('Start Automation: No scenario selected or already running.')
|
logger.warning('Start Automation: No scenario selected or already running.')
|
||||||
return
|
return
|
||||||
self.running = True
|
self.running = True
|
||||||
|
self.set_state('Looking for matches')
|
||||||
|
self.btn_start_stop.setText('Stop')
|
||||||
self.worker = threading.Thread(target=self.automation_loop, daemon=True)
|
self.worker = threading.Thread(target=self.automation_loop, daemon=True)
|
||||||
self.worker.start()
|
self.worker.start()
|
||||||
self.listener = keyboard.GlobalHotKeys({self.hotkey: self.stop_automation})
|
self.listener = keyboard.GlobalHotKeys({self.hotkey: self.stop_automation})
|
||||||
@@ -229,9 +245,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
def stop_automation(self):
|
def stop_automation(self):
|
||||||
logger.info('Stopping automation.')
|
logger.info('Stopping automation.')
|
||||||
self.running = False
|
self.running = False
|
||||||
|
self.set_state('Paused')
|
||||||
|
self.btn_start_stop.setText('Start')
|
||||||
if self.listener:
|
if self.listener:
|
||||||
self.listener.stop()
|
self.listener.stop()
|
||||||
self.listener = None
|
self.listener = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.setWindowTitle('Scenario Image Automation')
|
self.setWindowTitle('Scenario Image Automation')
|
||||||
@@ -268,11 +287,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.btn_rename_scenario.clicked.connect(self.rename_scenario)
|
self.btn_rename_scenario.clicked.connect(self.rename_scenario)
|
||||||
self.btn_rename_step = QtWidgets.QPushButton("Rename Step")
|
self.btn_rename_step = QtWidgets.QPushButton("Rename Step")
|
||||||
self.btn_rename_step.clicked.connect(self.rename_step)
|
self.btn_rename_step.clicked.connect(self.rename_step)
|
||||||
# Start/Stop
|
# Start/Stop Combined
|
||||||
self.btn_start = QtWidgets.QPushButton('Start')
|
self.btn_start_stop = QtWidgets.QPushButton('Start')
|
||||||
self.btn_start.clicked.connect(self.start_automation)
|
self.btn_start_stop.clicked.connect(self.toggle_automation)
|
||||||
self.btn_stop = QtWidgets.QPushButton('Stop')
|
# State label
|
||||||
self.btn_stop.clicked.connect(self.stop_automation)
|
self.state_label = QtWidgets.QLabel('State: Paused')
|
||||||
|
self.state_label.setStyleSheet('font-weight: bold; font-size: 16px; color: #0055aa;')
|
||||||
# Layout
|
# Layout
|
||||||
layout = QtWidgets.QGridLayout()
|
layout = QtWidgets.QGridLayout()
|
||||||
layout.addWidget(QtWidgets.QLabel('Scenario:'), 0, 0)
|
layout.addWidget(QtWidgets.QLabel('Scenario:'), 0, 0)
|
||||||
@@ -287,8 +307,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
layout.addWidget(self.btn_edit_step, 5, 2)
|
layout.addWidget(self.btn_edit_step, 5, 2)
|
||||||
layout.addWidget(self.btn_del_step, 5, 3)
|
layout.addWidget(self.btn_del_step, 5, 3)
|
||||||
layout.addWidget(self.btn_rename_step, 5, 4)
|
layout.addWidget(self.btn_rename_step, 5, 4)
|
||||||
layout.addWidget(self.btn_start, 6, 1)
|
layout.addWidget(self.btn_start_stop, 6, 1)
|
||||||
layout.addWidget(self.btn_stop, 6, 2)
|
layout.addWidget(self.state_label, 6, 2, 1, 3)
|
||||||
central = QtWidgets.QWidget()
|
central = QtWidgets.QWidget()
|
||||||
central.setLayout(layout)
|
central.setLayout(layout)
|
||||||
self.setCentralWidget(central)
|
self.setCentralWidget(central)
|
||||||
@@ -547,6 +567,10 @@ class StepDialog(QtWidgets.QDialog):
|
|||||||
self.btn_add_act.clicked.connect(self.add_action)
|
self.btn_add_act.clicked.connect(self.add_action)
|
||||||
self.btn_del_act = QtWidgets.QPushButton('Delete Action')
|
self.btn_del_act = QtWidgets.QPushButton('Delete Action')
|
||||||
self.btn_del_act.clicked.connect(self.delete_action)
|
self.btn_del_act.clicked.connect(self.delete_action)
|
||||||
|
self.btn_move_up_act = QtWidgets.QPushButton('Move Up')
|
||||||
|
self.btn_move_up_act.clicked.connect(self.move_action_up)
|
||||||
|
self.btn_move_down_act = QtWidgets.QPushButton('Move Down')
|
||||||
|
self.btn_move_down_act.clicked.connect(self.move_action_down)
|
||||||
# Layout
|
# Layout
|
||||||
layout = QtWidgets.QGridLayout()
|
layout = QtWidgets.QGridLayout()
|
||||||
layout.addWidget(QtWidgets.QLabel('Step Name:'), 0, 0)
|
layout.addWidget(QtWidgets.QLabel('Step Name:'), 0, 0)
|
||||||
@@ -572,6 +596,8 @@ class StepDialog(QtWidgets.QDialog):
|
|||||||
action_buttons = QtWidgets.QHBoxLayout()
|
action_buttons = QtWidgets.QHBoxLayout()
|
||||||
action_buttons.addWidget(self.btn_add_act)
|
action_buttons.addWidget(self.btn_add_act)
|
||||||
action_buttons.addWidget(self.btn_del_act)
|
action_buttons.addWidget(self.btn_del_act)
|
||||||
|
action_buttons.addWidget(self.btn_move_up_act)
|
||||||
|
action_buttons.addWidget(self.btn_move_down_act)
|
||||||
layout.addLayout(action_buttons, 5, 1, 1, 2)
|
layout.addLayout(action_buttons, 5, 1, 1, 2)
|
||||||
|
|
||||||
btns = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.StandardButton.Ok | QtWidgets.QDialogButtonBox.StandardButton.Cancel)
|
btns = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.StandardButton.Ok | QtWidgets.QDialogButtonBox.StandardButton.Cancel)
|
||||||
@@ -580,6 +606,22 @@ class StepDialog(QtWidgets.QDialog):
|
|||||||
layout.addWidget(btns, 6, 1, 1, 2)
|
layout.addWidget(btns, 6, 1, 1, 2)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def move_action_up(self):
|
||||||
|
idx = self.act_list.currentRow()
|
||||||
|
if idx > 0:
|
||||||
|
self.actions[idx-1], self.actions[idx] = self.actions[idx], self.actions[idx-1]
|
||||||
|
item = self.act_list.takeItem(idx)
|
||||||
|
self.act_list.insertItem(idx-1, item)
|
||||||
|
self.act_list.setCurrentRow(idx-1)
|
||||||
|
|
||||||
|
def move_action_down(self):
|
||||||
|
idx = self.act_list.currentRow()
|
||||||
|
if idx < len(self.actions) - 1 and idx >= 0:
|
||||||
|
self.actions[idx+1], self.actions[idx] = self.actions[idx], self.actions[idx+1]
|
||||||
|
item = self.act_list.takeItem(idx)
|
||||||
|
self.act_list.insertItem(idx+1, item)
|
||||||
|
self.act_list.setCurrentRow(idx+1)
|
||||||
|
|
||||||
class NameImageDialog(QtWidgets.QDialog):
|
class NameImageDialog(QtWidgets.QDialog):
|
||||||
def __init__(self, pixmap, parent=None):
|
def __init__(self, pixmap, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|||||||
Reference in New Issue
Block a user