ok-script 0.0.7__py3-none-any.whl

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.
Files changed (122) hide show
  1. autohelper/AutoHelper.py +116 -0
  2. autohelper/__init__.py +0 -0
  3. autohelper/capture/BaseCaptureMethod.py +30 -0
  4. autohelper/capture/HwndWindow.py +138 -0
  5. autohelper/capture/__init__.py +0 -0
  6. autohelper/capture/adb/ADBCaptureMethod.py +29 -0
  7. autohelper/capture/adb/DeviceManager.py +209 -0
  8. autohelper/capture/adb/__init__.py +0 -0
  9. autohelper/capture/adb/bin/__init__.py +0 -0
  10. autohelper/capture/adb/targets.py +61 -0
  11. autohelper/capture/adb/vbox.py +140 -0
  12. autohelper/capture/windows/WindowsGraphicsCaptureMethod.py +228 -0
  13. autohelper/capture/windows/__init__.py +0 -0
  14. autohelper/capture/windows/d3d11.py +74 -0
  15. autohelper/capture/windows/utils.py +149 -0
  16. autohelper/capture/windows/window.py +36 -0
  17. autohelper/color/Color.py +41 -0
  18. autohelper/color/__init__.py +0 -0
  19. autohelper/config/Config.py +79 -0
  20. autohelper/config/InfoDict.py +16 -0
  21. autohelper/config/__init__.py +0 -0
  22. autohelper/feature/Box.py +199 -0
  23. autohelper/feature/Feature.py +20 -0
  24. autohelper/feature/FeatureSet.py +207 -0
  25. autohelper/feature/FindFeature.py +52 -0
  26. autohelper/feature/__init__.py +0 -0
  27. autohelper/gui/App.py +120 -0
  28. autohelper/gui/Communicate.py +22 -0
  29. autohelper/gui/MainWindow.py +69 -0
  30. autohelper/gui/TabTitles.py +56 -0
  31. autohelper/gui/__init__.py +5 -0
  32. autohelper/gui/debug/AspectRatioWidget.py +31 -0
  33. autohelper/gui/debug/DebugTab.py +37 -0
  34. autohelper/gui/debug/FrameWidget.py +125 -0
  35. autohelper/gui/debug/InfoWidget.py +40 -0
  36. autohelper/gui/debug/LoggerWidget.py +74 -0
  37. autohelper/gui/debug/__init__.py +0 -0
  38. autohelper/gui/i18n/__init__.py +0 -0
  39. autohelper/gui/i18n/path.py +3 -0
  40. autohelper/gui/icon/__init__.py +0 -0
  41. autohelper/gui/icon/icon.py +6 -0
  42. autohelper/gui/loading/LoadingWindow.py +142 -0
  43. autohelper/gui/loading/__init__.py +0 -0
  44. autohelper/gui/overlay/OverlayWindow.py +34 -0
  45. autohelper/gui/overlay/__init__.py +0 -0
  46. autohelper/gui/resources.py +485 -0
  47. autohelper/gui/tasks/ConfigItemFactory.py +14 -0
  48. autohelper/gui/tasks/StartButton.py +47 -0
  49. autohelper/gui/tasks/TaskOpButton.py +33 -0
  50. autohelper/gui/tasks/TaskTab.py +121 -0
  51. autohelper/gui/tasks/TooltipTableWidget.py +39 -0
  52. autohelper/gui/tasks/__init__.py +0 -0
  53. autohelper/gui/util/Alert.py +20 -0
  54. autohelper/gui/util/InitWorker.py +17 -0
  55. autohelper/gui/util/__init__.py +0 -0
  56. autohelper/gui/widget/ListTableWidgetItem.py +27 -0
  57. autohelper/gui/widget/NumericTableWidgetItem.py +33 -0
  58. autohelper/gui/widget/RoundCornerContainer.py +59 -0
  59. autohelper/gui/widget/TabWidget.py +30 -0
  60. autohelper/gui/widget/UpdateConfigWidgetItem.py +16 -0
  61. autohelper/gui/widget/YesNonWidgetItem.py +23 -0
  62. autohelper/gui/widget/__init__.py +0 -0
  63. autohelper/interaction/ADBInteraction.py +33 -0
  64. autohelper/interaction/BaseInteraction.py +36 -0
  65. autohelper/interaction/Win32Interaction.py +56 -0
  66. autohelper/interaction/__init__.py +0 -0
  67. autohelper/logging/Logger.py +103 -0
  68. autohelper/logging/__init__.py +0 -0
  69. autohelper/ocr/OCR.py +50 -0
  70. autohelper/ocr/__init__.py +0 -0
  71. autohelper/predict/__init__.py +0 -0
  72. autohelper/predict/predict.py +45 -0
  73. autohelper/rotypes/Windows/Foundation/Collections.py +60 -0
  74. autohelper/rotypes/Windows/Foundation/__init__.py +153 -0
  75. autohelper/rotypes/Windows/Globalization/__init__.py +25 -0
  76. autohelper/rotypes/Windows/Graphics/Capture/__init__.py +110 -0
  77. autohelper/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +41 -0
  78. autohelper/rotypes/Windows/Graphics/DirectX/__init__.py +167 -0
  79. autohelper/rotypes/Windows/Graphics/Imaging/__init__.py +34 -0
  80. autohelper/rotypes/Windows/Graphics/__init__.py +5 -0
  81. autohelper/rotypes/Windows/Media/Ocr/__init__.py +76 -0
  82. autohelper/rotypes/Windows/Media/__init__.py +0 -0
  83. autohelper/rotypes/Windows/Security/Cryptography/__init__.py +18 -0
  84. autohelper/rotypes/Windows/Security/__init__.py +0 -0
  85. autohelper/rotypes/Windows/Storage/Streams/__init__.py +27 -0
  86. autohelper/rotypes/Windows/Storage/__init__.py +0 -0
  87. autohelper/rotypes/Windows/__init__.py +0 -0
  88. autohelper/rotypes/__init__.py +4 -0
  89. autohelper/rotypes/delegate.py +105 -0
  90. autohelper/rotypes/export.py +21 -0
  91. autohelper/rotypes/idldsl.py +272 -0
  92. autohelper/rotypes/inspectable.py +79 -0
  93. autohelper/rotypes/roapi.py +30 -0
  94. autohelper/rotypes/types.py +77 -0
  95. autohelper/rotypes/winstring.py +44 -0
  96. autohelper/save/BlackBarProcessor.py +25 -0
  97. autohelper/save/PostProcessor.py +6 -0
  98. autohelper/save/SaveByInterval.py +30 -0
  99. autohelper/save/SaveByKeyPress.py +27 -0
  100. autohelper/save/SaveMethodBase.py +46 -0
  101. autohelper/save/__init__.py +0 -0
  102. autohelper/scene/FeatureScene.py +14 -0
  103. autohelper/scene/Scene.py +21 -0
  104. autohelper/scene/__init__.py +0 -0
  105. autohelper/stats/StreamStats.py +34 -0
  106. autohelper/stats/__init__.py +0 -0
  107. autohelper/task/BaseTask.py +109 -0
  108. autohelper/task/ExecutorOperation.py +119 -0
  109. autohelper/task/FindFeatureTask.py +6 -0
  110. autohelper/task/TaskExecutor.py +249 -0
  111. autohelper/task/__init__.py +0 -0
  112. autohelper/util/__init__.py +0 -0
  113. autohelper/util/json.py +27 -0
  114. autohelper/util/list.py +2 -0
  115. autohelper/util/path.py +37 -0
  116. autohelper/util/thread.py +12 -0
  117. autohelper/util/win32_process.py +86 -0
  118. autohelper/util/yaml.py +28 -0
  119. ok_script-0.0.7.dist-info/METADATA +64 -0
  120. ok_script-0.0.7.dist-info/RECORD +122 -0
  121. ok_script-0.0.7.dist-info/WHEEL +5 -0
  122. ok_script-0.0.7.dist-info/top_level.txt +1 -0
autohelper/gui/App.py ADDED
@@ -0,0 +1,120 @@
1
+ import os
2
+ import sys
3
+
4
+ from PySide6.QtCore import QSize, QCoreApplication, QLocale, QTranslator
5
+ from PySide6.QtGui import QIcon
6
+ from PySide6.QtWidgets import QApplication, QStyleFactory, QMenu, QSystemTrayIcon
7
+
8
+ import autohelper
9
+ import autohelper.gui.resources
10
+ from autohelper.gui.Communicate import communicate
11
+ from autohelper.gui.MainWindow import MainWindow
12
+ from autohelper.gui.i18n.path import i18n_path
13
+ from autohelper.gui.loading.LoadingWindow import LoadingWindow
14
+ from autohelper.gui.overlay.OverlayWindow import OverlayWindow
15
+ from autohelper.logging.Logger import get_logger
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class App:
21
+ def __init__(self, icon=None, overlay=False, title="AutoUI", tasks=None,
22
+ exit_event=None):
23
+ super().__init__()
24
+ self.app = QApplication(sys.argv)
25
+ self.app.setStyle(QStyleFactory.create("Fusion"))
26
+ self.tasks = tasks
27
+ self.title = title
28
+ self.overlay = overlay
29
+ self.loading_window = None
30
+ self.overlay_window = None
31
+ self.main_window = None
32
+ self.exit_event = exit_event
33
+ self.icon = QIcon(icon or ":/icon/icon.ico")
34
+ self.tray = QSystemTrayIcon(self.icon)
35
+
36
+ locale = QLocale.system().name()
37
+ translator = QTranslator(self.app)
38
+ full_path = os.path.join(i18n_path, f"{QLocale().name()}")
39
+ if translator.load(QLocale().name(), ":/i18n"):
40
+ translator.setParent(self.app)
41
+ self.app.installTranslator(translator)
42
+ QCoreApplication.installTranslator(translator)
43
+ logger.debug(f"translator install success {QCoreApplication.translate('MainWindow', 'Debug')}")
44
+ else:
45
+ logger.debug(f"No translation available for {locale}, falling back to English/default. {full_path}")
46
+
47
+ # Create a context menu for the tray
48
+ menu = QMenu()
49
+ exit_action = menu.addAction("Exit")
50
+ exit_action.triggered.connect(self.quit)
51
+
52
+ # Set the context menu and show the tray icon
53
+ self.tray.setContextMenu(menu)
54
+ self.tray.show()
55
+
56
+ communicate.init.connect(self.on_init)
57
+ communicate.notification.connect(self.show_notification)
58
+
59
+ def show_notification(self, title, message):
60
+ if title is None:
61
+ title = self.title
62
+ self.tray.showMessage(title, message)
63
+
64
+ def show_loading(self):
65
+ self.loading_window = LoadingWindow(self, self.exit_event)
66
+ size = self.size_relative_to_screen(width=0.4, height=0.4)
67
+ self.loading_window.resize(size)
68
+ self.loading_window.setMinimumSize(size)
69
+ self.center_window(self.loading_window)
70
+ self.loading_window.show()
71
+
72
+ def center_window(self, window):
73
+ screen = self.app.primaryScreen()
74
+ size = screen.size()
75
+ # Calculate half the screen size
76
+ half_screen_width = size.width() / 2
77
+ half_screen_height = size.height() / 2
78
+
79
+ window.move(half_screen_width / 2, half_screen_height / 2)
80
+
81
+ def on_init(self, done, message):
82
+ if done:
83
+ self.loading_window.loading_done()
84
+ else:
85
+ self.loading_window.update_progress(message)
86
+
87
+ def show_main_window(self):
88
+ self.loading_window.close()
89
+ self.main_window = MainWindow(self.tasks, self.overlay, exit_event=self.exit_event)
90
+ self.main_window.setWindowTitle(self.title) # Set the window title here
91
+ self.main_window.setWindowIcon(self.icon)
92
+ if self.overlay and autohelper.gui.device_manager.hwnd is not None:
93
+ self.overlay_window = OverlayWindow(autohelper.gui.device_manager.hwnd)
94
+
95
+ size = self.size_relative_to_screen(width=0.5, height=0.6)
96
+ self.main_window.resize(size)
97
+ self.main_window.setMinimumSize(size)
98
+
99
+ # Optional: Move the window to the center of the screen
100
+
101
+ self.main_window.show()
102
+ self.main_window.raise_()
103
+ self.main_window.activateWindow()
104
+
105
+ def size_relative_to_screen(self, width, height):
106
+ screen = self.app.primaryScreen()
107
+ size = screen.size()
108
+ # Calculate half the screen size
109
+ half_screen_width = size.width() * width
110
+ half_screen_height = size.height() * height
111
+ # Resize the window to half the screen size
112
+ size = QSize(half_screen_width, half_screen_height)
113
+ return size
114
+
115
+ def exec(self):
116
+ sys.exit(self.app.exec())
117
+
118
+ def quit(self):
119
+ self.exit_event.set()
120
+ self.app.quit()
@@ -0,0 +1,22 @@
1
+ import numpy as np
2
+ from PySide6.QtCore import Signal, QObject
3
+
4
+
5
+ class Communicate(QObject):
6
+ frame = Signal(np.ndarray)
7
+ log = Signal(int, str)
8
+ fps = Signal(int)
9
+ frame_time = Signal(int)
10
+ scene = Signal(str)
11
+ draw_box = Signal(str, object, str)
12
+ tasks = Signal()
13
+ task_info = Signal()
14
+ window = Signal(bool, int, int, int, int, int, int, float)
15
+ loading_progress = Signal(str)
16
+ init = Signal(bool, str)
17
+ notification = Signal(str, str)
18
+ executor_paused: Signal = Signal(bool)
19
+ adb_devices: Signal = Signal()
20
+
21
+
22
+ communicate = Communicate()
@@ -0,0 +1,69 @@
1
+ from PySide6.QtCore import QObject, Signal, Slot
2
+ from PySide6.QtWidgets import QMessageBox, QTabWidget
3
+
4
+ from autohelper.gui.debug.DebugTab import DebugTab
5
+ from autohelper.gui.tasks.TaskTab import TaskTab
6
+ from autohelper.logging.Logger import get_logger
7
+
8
+ logger = get_logger(__name__)
9
+
10
+
11
+ class Communicate(QObject):
12
+ speak = Signal(str)
13
+
14
+
15
+ class MainWindow(QTabWidget):
16
+ def __init__(self, tasks, debug=False, exit_event=None):
17
+ super().__init__()
18
+ self.exit_event = exit_event
19
+ task_tab = TaskTab(tasks)
20
+ self.addTab(task_tab, self.tr("Task"))
21
+ if debug:
22
+ debug_tab = DebugTab()
23
+ self.addTab(debug_tab, self.tr("Debug"))
24
+ # ... Add other tabs similarly
25
+
26
+ # Styling the tabs and content if needed, for example:
27
+ self.setStyleSheet("""
28
+ QTabWidget::tab-bar {
29
+ alignment: center;
30
+ }
31
+ QTabBar::tab {
32
+ background: #333;
33
+ color: white;
34
+ border-radius: 5px;
35
+ padding: 10px;
36
+ }
37
+ QTabBar::tab:selected {
38
+ background: #555;
39
+ font-weight: bold;
40
+ }
41
+ QWidget {
42
+ background-color: #222;
43
+ color: #ddd;
44
+ }
45
+ """)
46
+ self.setWindowTitle("Close Event Example")
47
+ self.setTabPosition(QTabWidget.West)
48
+ # self.setTabBar(QTabBar())
49
+ self.comm = Communicate()
50
+ self.comm.speak.connect(self.say_hello)
51
+
52
+ @Slot(str)
53
+ def say_hello(self, message):
54
+ print(message)
55
+
56
+ def btn_clicked(self):
57
+ self.comm.speak.emit("Hello, PySide6 with parameters!")
58
+
59
+ def closeEvent(self, event):
60
+ # Create a message box that asks the user if they really want to close the window
61
+ reply = QMessageBox.question(self, 'Window Close', 'Are you sure you want to close the window?',
62
+ QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
63
+
64
+ if reply == QMessageBox.Yes:
65
+ self.exit_event.set()
66
+ event.accept()
67
+ logger.info("Window closed") # Place your code here
68
+ else:
69
+ event.ignore()
@@ -0,0 +1,56 @@
1
+ from PySide6.QtCore import QRect, QPoint, Qt
2
+ from PySide6.QtWidgets import QTabBar, QStylePainter, QStyleOptionTab, QStyle, QWidget
3
+ from PySide6.QtWidgets import QTabWidget, QVBoxLayout, QLabel
4
+
5
+
6
+ class TabBar(QTabBar):
7
+ def __init__(self, *args, **kwargs):
8
+ super().__init__(*args, **kwargs)
9
+
10
+ def tabSizeHint(self, index):
11
+ s = QTabBar.tabSizeHint(self, index)
12
+ if s.width() < s.height():
13
+ s.transpose()
14
+ s.scale(s.width() * 2, s.height() * 2, Qt.KeepAspectRatio)
15
+ return s
16
+
17
+ # Make text visible adequately
18
+ def paintEvent(self, event):
19
+ painter = QStylePainter(self)
20
+ style_option = QStyleOptionTab()
21
+
22
+ for i in range(self.count()):
23
+ self.initStyleOption(style_option, i)
24
+ painter.drawControl(QStyle.CE_TabBarTabShape, style_option)
25
+ painter.save()
26
+
27
+ s = style_option.rect.size()
28
+ s.scale(s.width() * 2, s.height() * 2, Qt.KeepAspectRatio)
29
+ rect = QRect(QPoint(), s)
30
+ rect.moveCenter(style_option.rect.center())
31
+ style_option.rect = rect
32
+
33
+ center = self.tabRect(i).center()
34
+ painter.translate(center)
35
+ painter.rotate(90)
36
+ painter.translate(center * -1)
37
+ painter.drawControl(QStyle.CE_TabBarTabLabel, style_option)
38
+ painter.restore()
39
+
40
+
41
+ class VerticalTabWidget(QTabWidget):
42
+ def __init__(self):
43
+ super().__init__()
44
+ self.setTabBar(TabBar(self))
45
+ self.setTabPosition(QTabWidget.West)
46
+
47
+ # def setTabSize(self, width, height):
48
+
49
+
50
+ class TabContent(QWidget):
51
+ def __init__(self, text):
52
+ super().__init__()
53
+ layout = QVBoxLayout()
54
+ label = QLabel(text)
55
+ layout.addWidget(label)
56
+ self.setLayout(layout)
@@ -0,0 +1,5 @@
1
+ from autohelper.capture.adb.DeviceManager import DeviceManager
2
+
3
+ executor = None
4
+ app = None
5
+ device_manager: DeviceManager | None = None
@@ -0,0 +1,31 @@
1
+ from PySide6.QtCore import QSize
2
+ from PySide6.QtWidgets import QWidget, QVBoxLayout, QSizePolicy
3
+
4
+
5
+ class AspectRatioWidget(QWidget):
6
+ def __init__(self, child_widget, aspect_ratio=16 / 9, parent=None):
7
+ super(AspectRatioWidget, self).__init__(parent)
8
+ self.aspect_ratio = aspect_ratio
9
+ self.child_widget = child_widget
10
+ self.layout = QVBoxLayout(self)
11
+ self.layout.addWidget(child_widget)
12
+ self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
13
+
14
+ def resizeEvent(self, event):
15
+ w = event.size().width()
16
+ h = event.size().height()
17
+ new_width = h * self.aspect_ratio
18
+ new_height = w / self.aspect_ratio
19
+ if new_height > h:
20
+ self.child_widget.setFixedSize(QSize(new_width, h))
21
+ else:
22
+ self.child_widget.setFixedSize(QSize(w, new_height))
23
+ super().resizeEvent(event)
24
+
25
+ def sizeHint(self):
26
+ # Provide a default size hint that respects the aspect ratio
27
+ height = 200 # Default height
28
+ return QSize(int(height * self.aspect_ratio), height)
29
+
30
+ def set_ratio(self, aspect_ratio):
31
+ self.aspect_ratio = aspect_ratio
@@ -0,0 +1,37 @@
1
+ from PySide6.QtCore import Qt
2
+ from PySide6.QtWidgets import QWidget, QGridLayout, QSplitter
3
+
4
+ from autohelper.gui.debug.FrameWidget import FrameWidget
5
+ from autohelper.gui.debug.InfoWidget import InfoWidget
6
+ from autohelper.gui.debug.LoggerWidget import LoggerWidget
7
+
8
+
9
+ class DebugTab(QWidget):
10
+ def __init__(self):
11
+ super().__init__()
12
+
13
+ self.mainLayout = QGridLayout()
14
+ self.setLayout(self.mainLayout)
15
+
16
+ # Top row setup with horizontal splitter
17
+ self.topSplitter = QSplitter(Qt.Horizontal)
18
+ self.topSplitter.setMinimumHeight(300)
19
+ self.info_widget = InfoWidget()
20
+ self.info_widget.setFixedWidth(200)
21
+ self.frame_widget = FrameWidget(True)
22
+ self.topSplitter.addWidget(self.info_widget)
23
+ self.topSplitter.addWidget(self.frame_widget)
24
+
25
+ # Bottom row setup
26
+ self.logger = LoggerWidget()
27
+
28
+ # Main splitter to handle top and bottom rows
29
+ self.mainSplitter = QSplitter(Qt.Vertical)
30
+ self.mainSplitter.addWidget(self.topSplitter)
31
+ self.mainSplitter.addWidget(self.logger)
32
+
33
+ # Add the main splitter to the layout
34
+ self.mainLayout.addWidget(self.mainSplitter, 0, 0)
35
+
36
+ self.mainSplitter.setStretchFactor(0, 8) # 30% for the top widget
37
+ self.mainSplitter.setStretchFactor(1, 2) # 70%
@@ -0,0 +1,125 @@
1
+ import time
2
+
3
+ import numpy as np
4
+ from PySide6.QtCore import Qt
5
+ from PySide6.QtGui import QPainter, QImage, QPixmap, QColor, QPen
6
+ from PySide6.QtWidgets import QWidget
7
+
8
+ from autohelper.feature.Box import Box
9
+ from autohelper.gui.Communicate import communicate
10
+
11
+
12
+ class FrameWidget(QWidget):
13
+ def __init__(self, draw_frame=False, parent=None):
14
+ super(FrameWidget, self).__init__(parent)
15
+ self.cv_image = None
16
+ self.color_map = {
17
+ "red": QColor(255, 0, 0), # RGB for red
18
+ "green": QColor(0, 255, 0), # RGB for green
19
+ "blue": QColor(0, 0, 255) # RGB for blue
20
+ }
21
+ self.uiDict = {}
22
+ self.time_to_expire = 3
23
+ self.draw_frame = draw_frame
24
+ self.frame_width = 1
25
+ self._visible = True
26
+ communicate.frame.connect(self.set_image)
27
+ communicate.draw_box.connect(self.draw_box)
28
+
29
+ def remove_expired(self):
30
+ current_time = time.time()
31
+ for key in list(self.uiDict.keys()):
32
+ # Filter out the old UI elements and keep the remaining ones
33
+ if current_time - self.uiDict[key][1] > self.time_to_expire:
34
+ del self.uiDict[key]
35
+
36
+ def draw_box(self, key: str, boxes, color=None):
37
+ if boxes is None:
38
+ return
39
+ if isinstance(boxes, Box):
40
+ boxes = [boxes]
41
+ if len(boxes) == 0:
42
+ return
43
+ timestamp = time.time()
44
+ brush = self.color_map.get(color, self.color_map.get("red"))
45
+ if key:
46
+ self.uiDict[key] = [boxes, timestamp, brush]
47
+ else:
48
+ for box in boxes:
49
+ self.uiDict[box.name] = [[box], timestamp, brush]
50
+ self.update()
51
+
52
+ def set_image(self, cv_image):
53
+ """Set the OpenCV image to be displayed."""
54
+ self.frame_width = cv_image.shape[1]
55
+ if self.draw_frame:
56
+ self.cv_image = cv_image
57
+ self.update() # Trigger a repaint
58
+
59
+ def paintEvent(self, event):
60
+ if not self._visible:
61
+ return
62
+ painter = QPainter(self)
63
+ x_offset = 0
64
+ y_offset = 0
65
+ if self.cv_image is not None:
66
+ frame = np.ascontiguousarray(self.cv_image)
67
+ # frame = self.cv_image
68
+ frame_height, frame_width = frame.shape[:2]
69
+
70
+ # Convert the OpenCV image (BGR) to QImage format (RGB)
71
+ # h, w, ch = self.cv_image.shape
72
+ # bytes_per_line = ch * w
73
+ # convert_to_Qt_format = QImage(self.cv_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
74
+ # qt_image = convert_to_Qt_format.rgbSwapped()
75
+
76
+ qt_image = QImage(frame.data, frame.shape[1], frame.shape[0],
77
+ frame.strides[0],
78
+ QImage.Format_BGR888)
79
+ # qt_image = QImage(frame.data, frame.shape[1], frame.shape[0],
80
+ # frame.strides[0],
81
+ # QImage.Format_RGBA8888)
82
+
83
+ # Scaling the image to fit the aspect ratio of the widget
84
+ qt_image = qt_image.scaled(self.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
85
+
86
+ # Calculate the position to center the image in the widget
87
+ x_offset = (self.width() - qt_image.width()) / 2
88
+ y_offset = (self.height() - qt_image.height()) / 2
89
+
90
+ frame_ratio = qt_image.width() / frame_width
91
+
92
+ painter.drawPixmap(x_offset, y_offset, QPixmap.fromImage(qt_image))
93
+ else:
94
+ frame_ratio = self.width() / self.frame_width
95
+ self.paint_border(painter)
96
+ self.paint_boxes(frame_ratio, painter, x_offset, y_offset)
97
+
98
+ def paint_boxes(self, frame_ratio, painter, x_offset, y_offset):
99
+ pen = QPen() # Set the brush to red color
100
+ pen.setWidth(2) # Set the width of the pen (border thickness)
101
+ painter.setPen(pen) # Apply the pen to the painter
102
+ painter.setBrush(Qt.NoBrush) # Ensure no fill
103
+ # painter.setFont(QFont('Arial', 12))
104
+ # Draw a square. Arguments are (x, y, width, height).
105
+ # Adjust these values according to the desired size and position.
106
+ self.remove_expired()
107
+ for key, value in self.uiDict.items():
108
+ boxes = value[0]
109
+ pen.setColor(value[2])
110
+ painter.setPen(pen)
111
+ for box in boxes:
112
+ width = box.width * frame_ratio
113
+ height = box.height * frame_ratio
114
+ x = x_offset + box.x * frame_ratio
115
+ y = y_offset + box.y * frame_ratio
116
+ painter.drawRect(x, y, width, height)
117
+ painter.drawText(x, y + height + 12, f"{box.name or key}_{round(box.confidence * 100)}")
118
+
119
+ def paint_border(self, painter):
120
+ pen = QPen(QColor(255, 0, 0, 255)) # Solid red color for the border
121
+ pen.setWidth(1) # Set the border width
122
+ painter.setPen(pen)
123
+
124
+ # Draw the border around the widget
125
+ painter.drawRect(0, 0, self.width() - 1, self.height() - 1)
@@ -0,0 +1,40 @@
1
+ from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
2
+
3
+ from autohelper.gui.Communicate import communicate
4
+
5
+
6
+ class InfoWidget(QWidget):
7
+
8
+ def __init__(self):
9
+ super().__init__()
10
+ self.init_ui()
11
+ # Connect the custom signal to the slot that updates the values
12
+ communicate.fps.connect(self.update_fps)
13
+ communicate.scene.connect(self.update_scene)
14
+ communicate.frame_time.connect(self.update_frame_time)
15
+
16
+ def init_ui(self):
17
+ self.layout = QVBoxLayout(self)
18
+
19
+ self.scene_widget = QLabel()
20
+ self.layout.addWidget(self.scene_widget)
21
+ self.update_scene("None")
22
+
23
+ self.fps_widget = QLabel()
24
+ self.layout.addWidget(self.fps_widget)
25
+ self.update_fps(0)
26
+
27
+ self.frame_time_widget = QLabel()
28
+ self.layout.addWidget(self.frame_time_widget)
29
+ self.update_frame_time(0)
30
+
31
+ self.layout.addStretch()
32
+
33
+ def update_fps(self, fps):
34
+ self.fps_widget.setText(f"FPS: {fps}")
35
+
36
+ def update_frame_time(self, fps):
37
+ self.frame_time_widget.setText(f"FrameTime: {fps}")
38
+
39
+ def update_scene(self, scene):
40
+ self.scene_widget.setText(f"Scene: {scene}")
@@ -0,0 +1,74 @@
1
+ import logging
2
+
3
+ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QComboBox, QLineEdit, QTextEdit)
4
+
5
+ from autohelper.gui.Communicate import communicate
6
+
7
+ level_map = {'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARNING': logging.WARNING, 'ERROR': logging.ERROR,
8
+ 'CRITICAL': logging.CRITICAL}
9
+
10
+
11
+ def get_colored_message(level, message):
12
+ if level >= logging.ERROR:
13
+ color = "red"
14
+ elif level == logging.WARNING:
15
+ color = "darkorange" # Dark yellow can be represented as 'darkorange' for better visibility
16
+ else:
17
+ return message
18
+ return f'<span style="color: {color};">{message}</span>'
19
+
20
+
21
+ class LoggerWidget(QWidget):
22
+ # Define log levels
23
+
24
+ def __init__(self, parent=None):
25
+ super(LoggerWidget, self).__init__(parent)
26
+ self.max_length = 1000
27
+ self.init_ui()
28
+ self.logs = [] # Store logs as tuples (level, message)
29
+ communicate.log.connect(self.add_log)
30
+
31
+ def init_ui(self):
32
+ self.layout = QVBoxLayout(self)
33
+
34
+ # Filter controls
35
+ controls_layout = QHBoxLayout()
36
+ self.level_filter = QComboBox()
37
+ self.level_filter.addItems(level_map.keys())
38
+ self.level_filter.currentTextChanged.connect(self.update_display)
39
+
40
+ self.text_filter = QLineEdit()
41
+ self.text_filter.setPlaceholderText("Filter logs by text...")
42
+ self.text_filter.textChanged.connect(self.update_display)
43
+
44
+ controls_layout.addWidget(self.level_filter)
45
+ controls_layout.addWidget(self.text_filter)
46
+
47
+ # Log display
48
+ self.log_display = QTextEdit()
49
+ self.log_display.setReadOnly(True)
50
+
51
+ # Add widgets to layout
52
+ self.layout.addLayout(controls_layout)
53
+ self.layout.addWidget(self.log_display)
54
+
55
+ def add_log(self, level, message):
56
+ self.logs.append((level, message))
57
+ if len(self.logs) > self.max_length:
58
+ # Calculate how many elements to remove
59
+ excess_length = len(self.logs) - self.max_length
60
+ # Remove the oldest elements
61
+ del self.logs[:excess_length]
62
+ self.update_display()
63
+
64
+ def update_display(self):
65
+ filtered_logs = self.filter_logs()
66
+ self.log_display.clear()
67
+ for level, message in filtered_logs:
68
+ colored_message = get_colored_message(level, message)
69
+ self.log_display.append(colored_message)
70
+
71
+ def filter_logs(self):
72
+ level = level_map[self.level_filter.currentText()]
73
+ text = self.text_filter.text().lower()
74
+ return [(lvl, msg) for lvl, msg in self.logs if (lvl >= level) and text in msg.lower()]
File without changes
File without changes
@@ -0,0 +1,3 @@
1
+ import os
2
+
3
+ i18n_path = os.path.dirname(__file__)
File without changes
@@ -0,0 +1,6 @@
1
+ import os
2
+
3
+ script_dir = os.path.dirname(os.path.realpath(__file__))
4
+
5
+ # Get the path of the file relative to the script
6
+ icon_path = os.path.join(script_dir, 'icon.ico')