ok-script 0.0.91__tar.gz → 0.0.94__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ok-script-0.0.91 → ok-script-0.0.94}/PKG-INFO +1 -1
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/OK.py +24 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/adb/DeviceManager.py +3 -3
- ok-script-0.0.94/ok/capture/windows/dump.py +83 -0
- ok-script-0.0.94/ok/feature/CompressCoco.py +61 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/feature/Feature.py +10 -4
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/feature/FeatureSet.py +73 -58
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/App.py +10 -9
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/MainWindow.py +4 -16
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/StartController.py +1 -1
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/DebugTab.py +19 -17
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/LogWindow.py +23 -24
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/resources.py +433 -432
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/start/StartCard.py +9 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/task/TaskExecutor.py +10 -7
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/update/GithubMultiDownloader.py +48 -11
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/update/Updater.py +14 -5
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/Handler.py +1 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok_script.egg-info/PKG-INFO +1 -1
- {ok-script-0.0.91 → ok-script-0.0.94}/setup.py +1 -1
- ok-script-0.0.91/ok/capture/windows/dump.py +0 -31
- ok-script-0.0.91/ok/feature/CompressCoco.py +0 -57
- {ok-script-0.0.91 → ok-script-0.0.94}/README.md +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/alas/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/alas/emulator_base.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/alas/emulator_windows.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/alas/platform_base.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/alas/platform_windows.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/alas/utils.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/BaseCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/HwndWindow.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/adb/ADBCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/adb/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/adb/bin/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/image/ImageCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/image/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/d3d11.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/utils.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/capture/windows/window.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/color/Color.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/color/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/config/Config.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/config/InfoDict.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/config/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/feature/Box.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/feature/FindFeature.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/feature/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/firebase/Analytics.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/firebase/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/Communicate.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/MessageWindow.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/TabTitles.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/about/AboutTab.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/about/HttpTextEdit.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/about/VersionCard.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/about/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/common/OKIcon.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/common/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/common/config.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/common/style_sheet.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/AspectRatioWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/FrameWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/InfoWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/Screenshot.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/debug/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/i18n/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/i18n/path.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/i18n/update.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/icon/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/icon/icon.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/overlay/OverlayWindow.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/overlay/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/qss/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/settings/SettingTab.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/settings/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/start/SelectCaptureListView.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/start/StartTab.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/start/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/ConfigItemFactory.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndDropDown.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndList.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/LabelAndWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/ModifyListDialog.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/ModifyListItem.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/StartButton.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/TaskCard.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/TaskOpButton.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/TooltipTableWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/TriggerTaskTab.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/tasks/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/util/Alert.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/util/InitWorker.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/util/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/Card.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/EmptyCard.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/FramelessDialog.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/ListTableWidgetItem.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/StartLoadingDialog.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/StatusBar.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/Tab.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/TabWidget.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/YesNonWidgetItem.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/gui/widget/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/interaction/ADBInteraction.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/interaction/BaseInteraction.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/interaction/DoNothingInteraction.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/interaction/Win32Interaction.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/interaction/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/logging/Logger.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/logging/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/ocr/OCR.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/ocr/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/Windows/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/delegate.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/export.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/idldsl.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/inspectable.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/roapi.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/types.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/rotypes/winstring.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/save/BlackBarProcessor.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/save/PostProcessor.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/save/SaveByInterval.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/save/SaveByKeyPress.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/save/SaveMethodBase.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/save/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/scene/FeatureScene.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/scene/Scene.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/scene/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/stats/StreamStats.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/stats/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/task/BaseTask.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/task/ExecutorOperation.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/task/TriggerTask.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/task/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/update/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/update/gen_md5.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/exit_event.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/json.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/list.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/path.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/thread.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/win32_process.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok/util/yaml.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok_script.egg-info/SOURCES.txt +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok_script.egg-info/requires.txt +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/ok_script.egg-info/top_level.txt +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/setup.cfg +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/tests/__init__.py +0 -0
- {ok-script-0.0.91 → ok-script-0.0.94}/tests/test_updater.py +0 -0
|
@@ -37,6 +37,9 @@ class OK:
|
|
|
37
37
|
config['debug'] = config.get("debug", False)
|
|
38
38
|
self.debug = config['debug']
|
|
39
39
|
try:
|
|
40
|
+
if self.debug:
|
|
41
|
+
import win32api
|
|
42
|
+
win32api.SetConsoleCtrlHandler(self.console_handler, True)
|
|
40
43
|
self.config = config
|
|
41
44
|
self.init_device_manager()
|
|
42
45
|
from ok.gui.debug.Screenshot import Screenshot
|
|
@@ -59,6 +62,7 @@ class OK:
|
|
|
59
62
|
if self.config.get("use_gui"):
|
|
60
63
|
if not self.init_error:
|
|
61
64
|
self.app.show_main_window()
|
|
65
|
+
logger.debug('start app.exec()')
|
|
62
66
|
self.app.exec()
|
|
63
67
|
else:
|
|
64
68
|
self.task_executor.start()
|
|
@@ -135,6 +139,26 @@ class OK:
|
|
|
135
139
|
while not self.exit_event.is_set():
|
|
136
140
|
time.sleep(1)
|
|
137
141
|
|
|
142
|
+
def console_handler(self, event):
|
|
143
|
+
import win32con
|
|
144
|
+
if event == win32con.CTRL_C_EVENT:
|
|
145
|
+
logger.info("CTRL+C event dump threads")
|
|
146
|
+
from ok.capture.windows.dump import dump_threads
|
|
147
|
+
dump_threads()
|
|
148
|
+
self.quit()
|
|
149
|
+
elif event == win32con.CTRL_CLOSE_EVENT:
|
|
150
|
+
logger.info("Close event quit")
|
|
151
|
+
self.quit()
|
|
152
|
+
elif event == win32con.CTRL_LOGOFF_EVENT:
|
|
153
|
+
logger.info("Logoff event quit")
|
|
154
|
+
self.quit()
|
|
155
|
+
elif event == win32con.CTRL_SHUTDOWN_EVENT:
|
|
156
|
+
logger.info("Shutdown event quit")
|
|
157
|
+
self.quit()
|
|
158
|
+
else: # Perform clean-up tasks here
|
|
159
|
+
print("Performing clean-up...")
|
|
160
|
+
return True
|
|
161
|
+
|
|
138
162
|
def quit(self):
|
|
139
163
|
logger.debug('quit app')
|
|
140
164
|
self.exit_event.set()
|
|
@@ -67,7 +67,7 @@ class DeviceManager:
|
|
|
67
67
|
logger.debug(f'adb_connect already connected {addr}')
|
|
68
68
|
return device
|
|
69
69
|
if try_connect:
|
|
70
|
-
self.adb.connect(addr, timeout=
|
|
70
|
+
self.adb.connect(addr, timeout=3)
|
|
71
71
|
logger.debug(f'adb_connect {addr}')
|
|
72
72
|
return self.adb_connect(addr, try_connect=False)
|
|
73
73
|
except AdbTimeout as e:
|
|
@@ -116,8 +116,8 @@ class DeviceManager:
|
|
|
116
116
|
if imei is not None:
|
|
117
117
|
preferred = self.get_preferred_device()
|
|
118
118
|
if current and preferred is not None and preferred['imei'] != imei:
|
|
119
|
-
logger.debug(f"refresh current only skip others {preferred['imei']} != imei")
|
|
120
|
-
|
|
119
|
+
logger.debug(f"refresh current only skip others {preferred['imei']} != {imei}")
|
|
120
|
+
continue
|
|
121
121
|
found = False
|
|
122
122
|
for device in self.device_dict.values():
|
|
123
123
|
if device.get('adb_imei') == imei:
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import signal
|
|
3
|
+
import sys
|
|
4
|
+
import threading
|
|
5
|
+
import traceback
|
|
6
|
+
|
|
7
|
+
from ok.util.path import get_path_relative_to_exe
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_thread_name(thread_id):
|
|
11
|
+
for thread in threading.enumerate():
|
|
12
|
+
if thread.ident == thread_id:
|
|
13
|
+
return thread.name
|
|
14
|
+
return "" # Return empty string if the thread name is not found
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def dump_threads():
|
|
18
|
+
# Get the stack trace for each thread
|
|
19
|
+
thread_dumps = []
|
|
20
|
+
for thread_id, frame in sys._current_frames().items():
|
|
21
|
+
thread_name = get_thread_name(thread_id)
|
|
22
|
+
thread_dump = f"Stack for thread {thread_id} (Name: {thread_name}):\n"
|
|
23
|
+
thread_dump += "".join(traceback.format_stack(frame))
|
|
24
|
+
thread_dumps.append(thread_dump)
|
|
25
|
+
|
|
26
|
+
# Write the thread dumps to a file
|
|
27
|
+
output_file = get_path_relative_to_exe(os.path.join('logs', "thread_dumps.txt"))
|
|
28
|
+
print(f'Dumping threads to {output_file}')
|
|
29
|
+
|
|
30
|
+
with open(output_file, "w") as file:
|
|
31
|
+
# Open the file with UTF-8 encoding
|
|
32
|
+
with open('file.txt', 'w', encoding='utf-8') as f:
|
|
33
|
+
f.write("\n\n".join(thread_dumps))
|
|
34
|
+
|
|
35
|
+
# subprocess.Popen(r'explorer /select,"{}"'.format(output_file))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def kill_dump():
|
|
39
|
+
print("Killing dump")
|
|
40
|
+
dump_threads()
|
|
41
|
+
sys.exit(0)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def console_handler(event):
|
|
45
|
+
import win32con
|
|
46
|
+
if event == win32con.CTRL_C_EVENT:
|
|
47
|
+
print("CTRL+C event")
|
|
48
|
+
dump_threads()
|
|
49
|
+
sys.exit(0)
|
|
50
|
+
elif event == win32con.CTRL_CLOSE_EVENT:
|
|
51
|
+
print("Close event")
|
|
52
|
+
elif event == win32con.CTRL_LOGOFF_EVENT:
|
|
53
|
+
print("Logoff event")
|
|
54
|
+
elif event == win32con.CTRL_SHUTDOWN_EVENT:
|
|
55
|
+
print("Shutdown event")
|
|
56
|
+
# Perform clean-up tasks here
|
|
57
|
+
print("Performing clean-up...")
|
|
58
|
+
# sys.exit(0) # Exit the program
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == '__main__':
|
|
63
|
+
|
|
64
|
+
import psutil
|
|
65
|
+
import faulthandler
|
|
66
|
+
|
|
67
|
+
# Enable the fault handler
|
|
68
|
+
faulthandler.enable()
|
|
69
|
+
|
|
70
|
+
# Iterate over all running processes
|
|
71
|
+
for proc in psutil.process_iter(['pid', 'name', 'status', 'exe']):
|
|
72
|
+
# Check if the process is unresponsive
|
|
73
|
+
# print(proc.info['exe'])
|
|
74
|
+
if proc.info['name'] == 'python.exe':
|
|
75
|
+
# Dump the traceback
|
|
76
|
+
print(f'dump {proc.pid} {proc.cmdline()} {proc.info["pid"] == os.getpid()}')
|
|
77
|
+
# faulthandler.dump_traceback(file=sys.stderr, all_threads=True)
|
|
78
|
+
# Kill the process
|
|
79
|
+
# os.kill(proc.info['pid'], signal.SIGTERM)
|
|
80
|
+
|
|
81
|
+
# faulthandler.dump_traceback(file=sys.stderr, all_threads=True)
|
|
82
|
+
# Kill the process
|
|
83
|
+
os.kill(16916, signal.SIGTERM)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import cv2
|
|
6
|
+
from PIL import Image
|
|
7
|
+
|
|
8
|
+
from ok.feature.FeatureSet import read_from_json
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def compress_coco(coco_json) -> None:
|
|
12
|
+
feature_dict, *_ = read_from_json(coco_json)
|
|
13
|
+
with open(coco_json, 'r') as file:
|
|
14
|
+
image_dict = {}
|
|
15
|
+
data = json.load(file)
|
|
16
|
+
coco_folder = os.path.dirname(coco_json)
|
|
17
|
+
image_map = {image['id']: image['file_name'] for image in data['images']}
|
|
18
|
+
category_map = {category['id']: category['name'] for category in data['categories']}
|
|
19
|
+
|
|
20
|
+
for annotation in data['annotations']:
|
|
21
|
+
image_id = annotation['image_id']
|
|
22
|
+
category_id = annotation['category_id']
|
|
23
|
+
|
|
24
|
+
feature = feature_dict.get(category_map[category_id])
|
|
25
|
+
if feature:
|
|
26
|
+
# Load and scale the image
|
|
27
|
+
image_path = str(os.path.join(coco_folder, image_map[image_id]))
|
|
28
|
+
image_features = image_dict.get(image_path, [])
|
|
29
|
+
image_features.append(feature)
|
|
30
|
+
image_dict[image_path] = image_features
|
|
31
|
+
|
|
32
|
+
# Loop through the image_dict and write all the image_feature associated with it in a new PNG
|
|
33
|
+
for image_path, features in image_dict.items():
|
|
34
|
+
background = None
|
|
35
|
+
for feature in features:
|
|
36
|
+
# Create a white background
|
|
37
|
+
if not background:
|
|
38
|
+
original_image = cv2.imread(image_path)
|
|
39
|
+
background = Image.new('RGBA', (original_image.shape[1], original_image.shape[0]),
|
|
40
|
+
(255, 255, 255, 255))
|
|
41
|
+
# Convert the OpenCV image (numpy array) to a PIL image
|
|
42
|
+
image = Image.fromarray(cv2.cvtColor(feature.mat, cv2.COLOR_BGR2RGBA))
|
|
43
|
+
background.paste(image, (feature.x, feature.y), image)
|
|
44
|
+
# Save the image with compression level 9
|
|
45
|
+
# background.save(image_path, 'PNG', optimize=True, compress_level=9)
|
|
46
|
+
|
|
47
|
+
# Add metadata
|
|
48
|
+
metadata = {
|
|
49
|
+
"ok_compressed": "1"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for key, value in metadata.items():
|
|
53
|
+
background.info[key] = value
|
|
54
|
+
|
|
55
|
+
# Save the image with metadata
|
|
56
|
+
background.save(image_path, 'PNG', optimize=True)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == '__main__':
|
|
60
|
+
json_file = sys.argv[1]
|
|
61
|
+
compress_coco(json_file)
|
|
@@ -14,10 +14,16 @@ class Feature:
|
|
|
14
14
|
height (int): The height of the bounding box.
|
|
15
15
|
"""
|
|
16
16
|
self.mat = mat
|
|
17
|
-
self.x = x
|
|
18
|
-
self.y = y
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
self.x = round(x)
|
|
18
|
+
self.y = round(y)
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def width(self):
|
|
22
|
+
return self.mat.shape[1]
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def height(self):
|
|
26
|
+
return self.mat.shape[0]
|
|
21
27
|
|
|
22
28
|
def __str__(self) -> str:
|
|
23
29
|
return f'self.x: {self.x}, self.y: {self.y}, width: {self.width}, height: {self.height}'
|
|
@@ -7,6 +7,7 @@ from typing import List
|
|
|
7
7
|
|
|
8
8
|
import cv2
|
|
9
9
|
import numpy as np
|
|
10
|
+
from PIL import Image
|
|
10
11
|
|
|
11
12
|
from ok.feature.Box import Box, sort_boxes
|
|
12
13
|
from ok.feature.Feature import Feature
|
|
@@ -33,7 +34,6 @@ class FeatureSet:
|
|
|
33
34
|
height (int): Scale images to this height.
|
|
34
35
|
"""
|
|
35
36
|
self.coco_json = resource_path(coco_json)
|
|
36
|
-
self.coco_folder = os.path.dirname(self.coco_json)
|
|
37
37
|
self.debug = debug
|
|
38
38
|
|
|
39
39
|
logger.debug(f'Loading features from {self.coco_json}')
|
|
@@ -67,59 +67,12 @@ class FeatureSet:
|
|
|
67
67
|
width (int): Target width for scaling images.
|
|
68
68
|
height (int): Target height for scaling images.
|
|
69
69
|
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if folder_size_mb > 5:
|
|
77
|
-
from ok.feature.CompressCoco import compress_coco
|
|
78
|
-
logger.info(f'template folder greater than 5MB try to compress the COCO dataset')
|
|
79
|
-
compress_coco(self.coco_json)
|
|
80
|
-
self.feature_dict.clear()
|
|
81
|
-
self.box_dict.clear()
|
|
82
|
-
with open(self.coco_json, 'r') as file:
|
|
83
|
-
data = json.load(file)
|
|
84
|
-
|
|
85
|
-
# Create a map from image ID to file name
|
|
86
|
-
image_map = {image['id']: image['file_name'] for image in data['images']}
|
|
87
|
-
|
|
88
|
-
# Create a map from category ID to category name
|
|
89
|
-
category_map = {category['id']: category['name'] for category in data['categories']}
|
|
90
|
-
|
|
91
|
-
for annotation in data['annotations']:
|
|
92
|
-
image_id = annotation['image_id']
|
|
93
|
-
category_id = annotation['category_id']
|
|
94
|
-
bbox = annotation['bbox']
|
|
95
|
-
|
|
96
|
-
# Load and scale the image
|
|
97
|
-
image_path = str(os.path.join(self.coco_folder, image_map[image_id]))
|
|
98
|
-
image = cv2.imread(image_path)
|
|
99
|
-
_, original_width = image.shape[:2]
|
|
100
|
-
if image is None:
|
|
101
|
-
logger.error(f'Could not read image {image_path}')
|
|
102
|
-
continue
|
|
103
|
-
x, y, w, h = bbox
|
|
104
|
-
if self.width != image.shape[1] or self.height != image.shape[0]:
|
|
105
|
-
scale_x, scale_y = self.width / image.shape[1], self.height / image.shape[0]
|
|
106
|
-
logger.debug(f'scaling images {scale_x}, {scale_y}')
|
|
107
|
-
image = cv2.resize(image, (self.width, self.height))
|
|
108
|
-
# Calculate the scaled bounding box
|
|
109
|
-
x, y, w, h = x * scale_x, y * scale_y, w * scale_x, h * scale_y
|
|
110
|
-
|
|
111
|
-
# Crop the image to the bounding box
|
|
112
|
-
image = image[round(y):round(y + h), round(x):round(x + w), :3]
|
|
113
|
-
|
|
114
|
-
# Store in featureDict using the category name
|
|
115
|
-
category_name = category_map[category_id]
|
|
116
|
-
logger.debug(
|
|
117
|
-
f"loaded {category_name} resized width {self.width} / original_width:{original_width},scale_x:{self.width / original_width}")
|
|
118
|
-
if category_name in self.feature_dict:
|
|
119
|
-
raise ValueError(f"Multiple boxes found for category {category_name}")
|
|
120
|
-
if not category_name.startswith('box_'):
|
|
121
|
-
self.feature_dict[category_name] = Feature(image, x, y, w, h)
|
|
122
|
-
self.box_dict[category_name] = Box(x, y, w, h, name=category_name)
|
|
70
|
+
self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height)
|
|
71
|
+
if self.debug and not compressed:
|
|
72
|
+
from ok.feature.CompressCoco import compress_coco
|
|
73
|
+
logger.info(f'coco not compressed try to compress the COCO dataset')
|
|
74
|
+
compress_coco(self.coco_json)
|
|
75
|
+
self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height)
|
|
123
76
|
|
|
124
77
|
def get_box_by_name(self, mat, category_name: str) -> Box:
|
|
125
78
|
self.check_size(mat)
|
|
@@ -235,6 +188,66 @@ class FeatureSet:
|
|
|
235
188
|
return result
|
|
236
189
|
|
|
237
190
|
|
|
191
|
+
def read_from_json(coco_json, width=-1, height=-1):
|
|
192
|
+
feature_dict = {}
|
|
193
|
+
box_dict = {}
|
|
194
|
+
ok_compressed = None
|
|
195
|
+
with open(coco_json, 'r') as file:
|
|
196
|
+
data = json.load(file)
|
|
197
|
+
coco_folder = os.path.dirname(coco_json)
|
|
198
|
+
|
|
199
|
+
# Create a map from image ID to file name
|
|
200
|
+
image_map = {image['id']: image['file_name'] for image in data['images']}
|
|
201
|
+
|
|
202
|
+
# Create a map from category ID to category name
|
|
203
|
+
category_map = {category['id']: category['name'] for category in data['categories']}
|
|
204
|
+
|
|
205
|
+
for image_id, file_name in image_map.items():
|
|
206
|
+
# Load and scale the image
|
|
207
|
+
image_path = str(os.path.join(coco_folder, file_name))
|
|
208
|
+
if ok_compressed is None:
|
|
209
|
+
image = Image.open(image_path)
|
|
210
|
+
ok_compressed = 'ok_compressed' in image.info.items()
|
|
211
|
+
whole_image = cv2.imread(image_path)
|
|
212
|
+
if whole_image is None:
|
|
213
|
+
logger.error(f'Could not read image {image_path}')
|
|
214
|
+
continue
|
|
215
|
+
_, original_width = whole_image.shape[:2]
|
|
216
|
+
|
|
217
|
+
if width != -1 and height != -1 and (width != whole_image.shape[1] or height != whole_image.shape[0]):
|
|
218
|
+
scale_x, scale_y = width / whole_image.shape[1], height / whole_image.shape[0]
|
|
219
|
+
logger.debug(f'scaling images {scale_x}, {scale_y} to {width}x{height}')
|
|
220
|
+
whole_image = cv2.resize(whole_image, (width, height))
|
|
221
|
+
else:
|
|
222
|
+
scale_x, scale_y = 1, 1
|
|
223
|
+
|
|
224
|
+
for annotation in data['annotations']:
|
|
225
|
+
if image_id != annotation['image_id']:
|
|
226
|
+
continue
|
|
227
|
+
|
|
228
|
+
category_id = annotation['category_id']
|
|
229
|
+
bbox = annotation['bbox']
|
|
230
|
+
x, y, w, h = bbox
|
|
231
|
+
|
|
232
|
+
# Calculate the scaled bounding box
|
|
233
|
+
x, y, w, h = x * scale_x, y * scale_y, w * scale_x, h * scale_y
|
|
234
|
+
|
|
235
|
+
# Crop the image to the bounding box
|
|
236
|
+
image = whole_image[round(y):round(y + h), round(x):round(x + w), :3]
|
|
237
|
+
|
|
238
|
+
# Store in featureDict using the category name
|
|
239
|
+
category_name = category_map[category_id]
|
|
240
|
+
logger.debug(
|
|
241
|
+
f"loaded {category_name} resized width {width} / original_width:{original_width},scale_x:{width / original_width}")
|
|
242
|
+
if category_name in feature_dict:
|
|
243
|
+
raise ValueError(f"Multiple boxes found for category {category_name}")
|
|
244
|
+
if not category_name.startswith('box_'):
|
|
245
|
+
feature_dict[category_name] = Feature(image, x, y, w, h)
|
|
246
|
+
box_dict[category_name] = Box(x, y, w, h, name=category_name)
|
|
247
|
+
|
|
248
|
+
return feature_dict, box_dict, ok_compressed
|
|
249
|
+
|
|
250
|
+
|
|
238
251
|
def filter_and_sort_matches(result, threshold, width, height):
|
|
239
252
|
# Filter matches based on the threshold
|
|
240
253
|
loc = np.where(result >= threshold)
|
|
@@ -242,13 +255,15 @@ def filter_and_sort_matches(result, threshold, width, height):
|
|
|
242
255
|
# Zip the locations into a list of tuples and sort by threshold in descending order
|
|
243
256
|
matches = sorted(zip(*loc[::-1]), key=lambda p: result[p[::-1]], reverse=True)
|
|
244
257
|
|
|
258
|
+
# Sort matches based on their location
|
|
259
|
+
matches.sort(key=lambda pt: (pt[0], pt[1]))
|
|
260
|
+
|
|
245
261
|
# Filter out overlapping matches
|
|
246
262
|
unique_matches = []
|
|
247
263
|
for pt in matches:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
264
|
+
# Only compare with the last match in unique_matches
|
|
265
|
+
if not unique_matches or not (unique_matches[-1][0] <= pt[0] <= unique_matches[-1][0] + width and
|
|
266
|
+
unique_matches[-1][1] <= pt[1] <= unique_matches[-1][1] + height):
|
|
251
267
|
unique_matches.append(pt)
|
|
252
268
|
|
|
253
|
-
# print(f"result {len(result)} loc {len(loc)} matches {len(matches)} unique_matches {unique_matches}")
|
|
254
269
|
return unique_matches
|
|
@@ -13,7 +13,6 @@ from ok.gui.Communicate import communicate
|
|
|
13
13
|
from ok.gui.MainWindow import MainWindow
|
|
14
14
|
from ok.gui.MessageWindow import MessageWindow
|
|
15
15
|
from ok.gui.StartController import StartController
|
|
16
|
-
from ok.gui.debug.LogWindow import LogWindow
|
|
17
16
|
from ok.gui.i18n.path import i18n_path
|
|
18
17
|
from ok.gui.overlay.OverlayWindow import OverlayWindow
|
|
19
18
|
from ok.logging.Logger import get_logger
|
|
@@ -95,26 +94,28 @@ class App:
|
|
|
95
94
|
self.show_message_window(title, content)
|
|
96
95
|
|
|
97
96
|
def show_main_window(self):
|
|
97
|
+
|
|
98
|
+
if self.overlay and ok.gui.device_manager.hwnd is not None:
|
|
99
|
+
self.overlay_window = OverlayWindow(ok.gui.device_manager.hwnd)
|
|
100
|
+
|
|
101
|
+
if self.config.get('debug'):
|
|
102
|
+
from ok.gui.debug.LogWindow import LogWindow
|
|
103
|
+
self.log_window = LogWindow(self.config)
|
|
104
|
+
self.log_window.show()
|
|
105
|
+
logger.debug('showing log_window')
|
|
106
|
+
|
|
98
107
|
self.main_window = MainWindow(self.config, self.icon, self.title, self.version, self.overlay, self.about,
|
|
99
108
|
self.exit_event)
|
|
100
109
|
# Set the window title here
|
|
101
110
|
self.main_window.setWindowIcon(self.icon)
|
|
102
|
-
if self.overlay and ok.gui.device_manager.hwnd is not None:
|
|
103
|
-
self.overlay_window = OverlayWindow(ok.gui.device_manager.hwnd)
|
|
104
111
|
|
|
105
112
|
size = self.size_relative_to_screen(width=0.5, height=0.6)
|
|
106
113
|
self.main_window.resize(size)
|
|
107
114
|
self.main_window.setMinimumSize(size)
|
|
108
115
|
|
|
109
|
-
# Optional: Move the window to the center of the screen
|
|
110
|
-
|
|
111
116
|
self.main_window.show()
|
|
112
117
|
self.main_window.raise_()
|
|
113
118
|
self.main_window.activateWindow()
|
|
114
|
-
if self.config.get('debug'):
|
|
115
|
-
self.log_window = LogWindow(self.config)
|
|
116
|
-
self.log_window.show()
|
|
117
|
-
logger.debug('showing log_window')
|
|
118
119
|
|
|
119
120
|
def size_relative_to_screen(self, width, height):
|
|
120
121
|
screen = self.app.primaryScreen()
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import sys
|
|
3
2
|
|
|
4
3
|
from PySide6.QtCore import QObject, Signal, Qt
|
|
5
4
|
from PySide6.QtWidgets import QMenu, QSystemTrayIcon
|
|
6
|
-
from qfluentwidgets import FluentIcon, NavigationItemPosition, MSFluentWindow, InfoBar, InfoBarPosition
|
|
5
|
+
from qfluentwidgets import FluentIcon, NavigationItemPosition, MSFluentWindow, InfoBar, InfoBarPosition
|
|
7
6
|
|
|
8
7
|
import ok.gui
|
|
9
8
|
from ok.gui.Communicate import communicate
|
|
@@ -158,22 +157,11 @@ class MainWindow(MSFluentWindow):
|
|
|
158
157
|
self.comm.speak.emit("Hello, PySide6 with parameters!")
|
|
159
158
|
|
|
160
159
|
def closeEvent(self, event):
|
|
161
|
-
# Create a message box that asks the user if they really want to close the window
|
|
162
|
-
if sys.platform == 'win32' and 'shutdown' in os.environ.get('SESSIONNAME', '').lower():
|
|
163
|
-
logger.info("system shutting down")
|
|
164
|
-
ok.gui.ok.quit()
|
|
165
|
-
event.accept()
|
|
166
|
-
return
|
|
167
|
-
|
|
168
160
|
if ok.gui.ok.exit_event.is_set():
|
|
161
|
+
logger.info("Window closed exit_event.is_set")
|
|
169
162
|
event.accept()
|
|
170
163
|
return
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
w = MessageBox(title, content, self.window())
|
|
174
|
-
if w.exec():
|
|
175
|
-
logger.info("Window closed")
|
|
164
|
+
else:
|
|
165
|
+
logger.info("Window closed exit_event.is not set")
|
|
176
166
|
ok.gui.ok.quit()
|
|
177
167
|
event.accept()
|
|
178
|
-
else:
|
|
179
|
-
event.ignore()
|
|
@@ -39,7 +39,7 @@ class StartController(QObject):
|
|
|
39
39
|
error = self.check_device_error()
|
|
40
40
|
if error is None:
|
|
41
41
|
break
|
|
42
|
-
logger.
|
|
42
|
+
logger.error(f'waiting for game to start error {error}')
|
|
43
43
|
remaining_time = wait_until - time.time()
|
|
44
44
|
if remaining_time <= 0:
|
|
45
45
|
communicate.starting_emulator.emit(True, self.tr('Start game timeout!'), 0)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
from ctypes import windll, wintypes
|
|
3
3
|
|
|
4
|
-
from PySide6.QtCore import Qt, Signal
|
|
4
|
+
from PySide6.QtCore import Qt, Signal, QCoreApplication
|
|
5
5
|
from PySide6.QtWidgets import QWidget, QFileDialog, QCompleter, QVBoxLayout, QHBoxLayout
|
|
6
6
|
from _ctypes import byref
|
|
7
7
|
from qfluentwidgets import PushButton, FlowLayout, ComboBox, SearchLineEdit, TextEdit
|
|
@@ -46,7 +46,7 @@ class DebugTab(Tab):
|
|
|
46
46
|
# self.dump_shortcut.activated.connect(dump_threads)
|
|
47
47
|
|
|
48
48
|
capture_button = PushButton(self.tr("Capture Screenshot"))
|
|
49
|
-
capture_button.clicked.connect(lambda: self.handler.post(
|
|
49
|
+
capture_button.clicked.connect(lambda: self.handler.post(capture))
|
|
50
50
|
layout.addWidget(capture_button)
|
|
51
51
|
|
|
52
52
|
ocr_button = PushButton("OCR")
|
|
@@ -202,20 +202,22 @@ class DebugTab(Tab):
|
|
|
202
202
|
self.select_screenshot_button.setText(self.tr("Drop or Select Screenshot"))
|
|
203
203
|
self.config['target_images'] = None
|
|
204
204
|
|
|
205
|
-
def capture(self):
|
|
206
|
-
if ok.gui.device_manager.capture_method is not None:
|
|
207
|
-
logger.info(f'ok.gui.device_manager.capture_method {ok.gui.device_manager.capture_method}')
|
|
208
|
-
capture = str(ok.gui.device_manager.capture_method)
|
|
209
|
-
frame = ok.gui.device_manager.capture_method.do_get_frame()
|
|
210
|
-
if frame is not None:
|
|
211
|
-
file_path = ok.gui.ok.screenshot.generate_screen_shot(frame, ok.gui.ok.screenshot.ui_dict,
|
|
212
|
-
ok.gui.ok.screenshot.screenshot_folder, capture)
|
|
213
205
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
206
|
+
def capture():
|
|
207
|
+
if ok.gui.device_manager.capture_method is not None:
|
|
208
|
+
logger.info(f'ok.gui.device_manager.capture_method {ok.gui.device_manager.capture_method}')
|
|
209
|
+
current_capture = str(ok.gui.device_manager.capture_method)
|
|
210
|
+
frame = ok.gui.device_manager.capture_method.do_get_frame()
|
|
211
|
+
if frame is not None:
|
|
212
|
+
file_path = ok.gui.ok.screenshot.generate_screen_shot(frame, ok.gui.ok.screenshot.ui_dict,
|
|
213
|
+
ok.gui.ok.screenshot.screenshot_folder,
|
|
214
|
+
current_capture)
|
|
215
|
+
|
|
216
|
+
# Use subprocess.Popen to open the file explorer and select the file
|
|
217
|
+
subprocess.Popen(r'explorer /select,"{}"'.format(file_path))
|
|
218
|
+
logger.info(f'captured screenshot: {current_capture}')
|
|
219
|
+
alert_info(QCoreApplication.translate('DebugTab', 'Capture Success'), True)
|
|
220
220
|
else:
|
|
221
|
-
alert_error(
|
|
221
|
+
alert_error(QCoreApplication.translate('DebugTab', 'Capture returned None'))
|
|
222
|
+
else:
|
|
223
|
+
alert_error(QCoreApplication.translate('DebugTab', 'No Capture Available or Selected'))
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from PySide6.QtCore import Qt, QAbstractListModel,
|
|
1
|
+
from PySide6.QtCore import Qt, QAbstractListModel, QPoint, QModelIndex
|
|
2
2
|
from PySide6.QtGui import QColor
|
|
3
|
-
from PySide6.QtWidgets import
|
|
4
|
-
|
|
3
|
+
from PySide6.QtWidgets import QWidget, \
|
|
4
|
+
QStyledItemDelegate, QListView, QVBoxLayout, QHBoxLayout, QAbstractItemView, QComboBox, QLineEdit, QLabel, \
|
|
5
|
+
QPushButton
|
|
5
6
|
|
|
6
7
|
from ok.config.Config import Config
|
|
7
8
|
from ok.gui.Communicate import communicate
|
|
@@ -39,19 +40,19 @@ class ColorDelegate(QStyledItemDelegate):
|
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class LogModel(QAbstractListModel):
|
|
42
|
-
def __init__(self
|
|
43
|
+
def __init__(self):
|
|
43
44
|
super(LogModel, self).__init__()
|
|
44
|
-
self.log_list = log_list
|
|
45
45
|
self.logs = []
|
|
46
|
-
self.filtered_logs =
|
|
46
|
+
self.filtered_logs = []
|
|
47
47
|
self.current_level = "ALL"
|
|
48
48
|
self.current_keyword = ""
|
|
49
49
|
|
|
50
50
|
def data(self, index, role):
|
|
51
|
-
if
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
if 0 <= index.row() < len(self.filtered_logs):
|
|
52
|
+
if role == Qt.DisplayRole:
|
|
53
|
+
return self.filtered_logs[index.row()].text
|
|
54
|
+
elif role == Qt.ForegroundRole:
|
|
55
|
+
return self.filtered_logs[index.row()].format
|
|
55
56
|
|
|
56
57
|
def rowCount(self, index):
|
|
57
58
|
return len(self.filtered_logs)
|
|
@@ -62,15 +63,15 @@ class LogModel(QAbstractListModel):
|
|
|
62
63
|
colored_text = ColoredText(message, color_format, level)
|
|
63
64
|
self.logs.append(colored_text)
|
|
64
65
|
if len(self.logs) >= 500:
|
|
65
|
-
self.beginRemoveRows(QModelIndex(), 0, 0)
|
|
66
|
+
# self.beginRemoveRows(QModelIndex(), 0, 0)
|
|
66
67
|
self.logs.pop(0)
|
|
67
|
-
self.endRemoveRows()
|
|
68
|
-
|
|
68
|
+
# self.endRemoveRows()
|
|
69
69
|
self.beginInsertRows(QModelIndex(), self.rowCount(QModelIndex()), self.rowCount(QModelIndex()))
|
|
70
70
|
self.do_filter_logs()
|
|
71
71
|
self.endInsertRows()
|
|
72
|
-
|
|
73
|
-
self.
|
|
72
|
+
|
|
73
|
+
# self.layoutChanged.emit()
|
|
74
|
+
# self.log_list.scrollToBottom()
|
|
74
75
|
|
|
75
76
|
def do_filter_logs(self):
|
|
76
77
|
|
|
@@ -92,9 +93,10 @@ class LogModel(QAbstractListModel):
|
|
|
92
93
|
def filter_logs(self, level, keyword):
|
|
93
94
|
self.current_level = level
|
|
94
95
|
self.current_keyword = keyword
|
|
96
|
+
self.beginRemoveRows(QModelIndex(), 0, self.rowCount(QModelIndex()) - 1)
|
|
97
|
+
self.filtered_logs.clear()
|
|
98
|
+
self.endRemoveRows()
|
|
95
99
|
self.do_filter_logs()
|
|
96
|
-
self.layoutChanged.emit()
|
|
97
|
-
self.log_list.scrollToBottom()
|
|
98
100
|
|
|
99
101
|
def get_color_format(self, level):
|
|
100
102
|
# Define color codes for different levels
|
|
@@ -118,8 +120,6 @@ class LogWindow(QWidget):
|
|
|
118
120
|
app_config.get('config_folder'), 'log_window')
|
|
119
121
|
self.setGeometry(self.config['x'], self.config['y'], self.config['width'], self.config['height'])
|
|
120
122
|
|
|
121
|
-
self.refresh_signal = Signal()
|
|
122
|
-
|
|
123
123
|
self.old_pos = None
|
|
124
124
|
|
|
125
125
|
# Layouts
|
|
@@ -158,16 +158,15 @@ class LogWindow(QWidget):
|
|
|
158
158
|
|
|
159
159
|
self.setLayout(self.layout)
|
|
160
160
|
|
|
161
|
-
self.log_model = LogModel(
|
|
161
|
+
self.log_model = LogModel()
|
|
162
162
|
self.log_list.setModel(self.log_model)
|
|
163
|
-
communicate.log.connect(self.add_log)
|
|
164
163
|
|
|
165
|
-
self.
|
|
166
|
-
self.filter_logs()
|
|
164
|
+
communicate.log.connect(self.add_log)
|
|
167
165
|
|
|
168
166
|
def add_log(self, level_no, message):
|
|
169
|
-
|
|
167
|
+
# print('add_log', level_no, message)
|
|
170
168
|
self.log_model.add_log(log_levels.get(level_no, 'DEBUG'), message)
|
|
169
|
+
self.log_list.scrollToBottom()
|
|
171
170
|
|
|
172
171
|
def filter_logs(self):
|
|
173
172
|
level = self.level_filter.currentText()
|