diff --git a/README.md b/README.md
index 0edeee8..0f7ff2e 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,6 @@
Simple and nice keyboard to chat message bindings maker.
Made especially for RAGE:MP.
-(для тех у кого не работает - выключите проверку на RAGE MP в настройках)
-

## How to use source code:
@@ -14,10 +12,10 @@ Made especially for RAGE:MP.
5. Install `pip` requirements using `pip install -r requirements.txt`
6. Enjoy!
-## Converting .ui (**QT Designer**) to .py:
+## Translating .ui (**QT Designer**) to .py:
1. Go to root of project.
-2. Execute `tools\compileUI.py`
+2. Execute `tools\translateUI.bat`
## Building:
1. Go to root of project.
-2. Execute `tools\build_full.bat`
+2. Execute `tools\build.bat`
diff --git a/installer.iss b/installer.iss
index 383b35b..76175db 100644
--- a/installer.iss
+++ b/installer.iss
@@ -6,15 +6,15 @@
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{9D6C1B9B-8B69-4803-9761-F4DA08BBB0B1}
AppName=ArciBinder
-AppVersion=1.2.1
-;AppVerName=ArciBinder 1.2.1
+AppVersion=1.2.2
+;AppVerName=ArciBinder 1.2.2
AppPublisher=Denipolis
DefaultDirName={autopf}\ArciBinder
DisableProgramGroupPage=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=build\
-OutputBaseFilename=ArciBinder_win32_installer
+OutputBaseFilename=arcibinder{#SetupSetting("AppVersion")}_setup
SetupIconFile=src\ui\images\logo.ico
Compression=lzma
SolidCompression=yes
diff --git a/src/binder.py b/src/binder.py
index 4739e2c..c1516de 100644
--- a/src/binder.py
+++ b/src/binder.py
@@ -26,7 +26,7 @@ def updateProfiles(self):
keyboard.add_hotkey(profile[2], self.playProfile, args=(str(profile[1]),))
def playProfile(self, profileName: str):
- if self.database.isSettingEnabled('dontCheckForName') or (rageMpTitle in utils.getActiveWindowTitle()):
+ if not self.database.isSettingEnabled('checkFullScreen') or utils.isAppFullScreen():
profileStrings = self.database.findStringsInProfile(profileName)
for profileString in profileStrings:
diff --git a/src/main.py b/src/main.py
index c32084d..40307ea 100644
--- a/src/main.py
+++ b/src/main.py
@@ -69,6 +69,7 @@ def __showWithUuid(self, uuid: str) -> None:
currentRowCooldown.setText(str(profileStrings[i][1]))
else:
self.uuid = uuidlib.uuid4().hex
+ self.ui.createProfileButton.setText('Создать')
def createProfileButtonCallback(self):
if not self.ui.profileName.text():
@@ -135,8 +136,8 @@ def rebuildUI(self):
self.ui.autorunCheckbox.setChecked(utils.isAutoRun())
self.ui.autorunCheckbox.stateChanged.connect(lambda state: utils.enableAutoRun() if state == 2 else utils.disableAutoRun())
- self.ui.nameCheckbox.setChecked(database.isSettingEnabled('dontCheckForName'))
- self.ui.nameCheckbox.stateChanged.connect(lambda state: database.setSettingValue('dontCheckForName', state))
+ self.ui.nameCheckbox.setChecked(database.isSettingEnabled('checkFullScreen'))
+ self.ui.nameCheckbox.stateChanged.connect(lambda state: database.setSettingValue('checkFullScreen', state))
for profile in database.findAllProfiles():
self.ui.listWidget.addItem(profile[0])
@@ -198,7 +199,7 @@ def main():
app.setApplicationName('ArciBinder')
app.setApplicationDisplayName('ArciBinder')
- app.setApplicationVersion('1.2.1')
+ app.setApplicationVersion('1.2.2')
app.setWindowIcon(QIcon(os.path.join(basedir, "ui/images/logo.ico")))
if QFontDatabase.addApplicationFont(u":/fonts/fonts/Rubik-SemiBold.ttf") < 0: print('Unable to load font!')
diff --git a/src/ui/mainWindow.ui b/src/ui/mainWindow.ui
index a3f73a6..585e35e 100644
--- a/src/ui/mainWindow.ui
+++ b/src/ui/mainWindow.ui
@@ -148,6 +148,9 @@ QPushButton::pressed {
41
+
+ Профили
+
@@ -171,6 +174,9 @@ QPushButton::pressed {
41
+
+ Настройки
+
@@ -203,6 +209,9 @@ QPushButton::pressed {
-1
+
+ GitHub разработчика
+
@@ -289,6 +298,9 @@ QPushButton::pressed {
-1
+
+ При нажатии крестика приложение будет не выключаться, а скрываться в панель задач.
+
Прятать приложение в трей при нажатии кнопки "Закрыть"
@@ -308,8 +320,11 @@ QPushButton::pressed {
-1
+
+ Запускает приложение автоматически вместе с системой.
+
- Запускать приложение вместе с системой (автозапуск)
+ Запускать приложение вместе с системой (автозагрузка)
@@ -327,8 +342,11 @@ QPushButton::pressed {
-1
+
+ Нужно, если вы хотите что бы биндер работал только в игре. Не работает, если игра запущена в окне.
+
- Использовать бинды не только в RAGE Multiplayer
+ Проверять, открыто ли полноэкранное приложение
@@ -368,6 +386,9 @@ QPushButton::pressed {
-1
+
+ Создать новый профиль
+
@@ -403,6 +424,9 @@ QPushButton::pressed {
-1
+
+ Изменить выбранный профиль
+
@@ -438,6 +462,9 @@ QPushButton::pressed {
-1
+
+ Удалить выбранный профиль
+
@@ -486,6 +513,9 @@ QPushButton::pressed {
321
+
+ Список ваших созданных профилей, пусто если нету ни одного созданного профиля.
+
diff --git a/src/ui/profileEditWindow.ui b/src/ui/profileEditWindow.ui
index 20fed35..efea0ab 100644
--- a/src/ui/profileEditWindow.ui
+++ b/src/ui/profileEditWindow.ui
@@ -7,7 +7,7 @@
0
0
967
- 503
+ 518
@@ -52,8 +52,8 @@ QListWidget {
- 410
- 460
+ 400
+ 470
181
31
@@ -86,8 +86,8 @@ QListWidget {
- 550
- 400
+ 540
+ 410
91
21
@@ -106,12 +106,15 @@ QListWidget {
Клавиша
+
+ Qt::AlignCenter
+
- 550
- 430
+ 540
+ 440
91
21
@@ -132,8 +135,8 @@ QListWidget {
- 340
- 430
+ 330
+ 440
181
21
@@ -145,8 +148,8 @@ QListWidget {
- 340
- 400
+ 330
+ 410
191
20
@@ -170,7 +173,7 @@ QListWidget {
20
- 50
+ 60
921
341
@@ -744,6 +747,42 @@ QListWidget {
Редактор
+
+
+
+ 30
+ 50
+ 41
+ 16
+
+
+
+
+ 10
+
+
+
+ Текст
+
+
+
+
+
+ 810
+ 50
+ 61
+ 16
+
+
+
+
+ 10
+
+
+
+ Задержка
+
+
diff --git a/src/utils.py b/src/utils.py
index 71ae407..4603793 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -3,7 +3,8 @@
import os
import winreg as reg
import sys
-from ctypes import wintypes, windll, create_unicode_buffer
+from ctypes import windll
+import win32gui
def singleKeyPress(key: str) -> None:
keyboard.press(key)
@@ -14,16 +15,16 @@ def singleKeyPress(key: str) -> None:
def quit() -> None:
os._exit(0)
-def getActiveWindowTitle() -> str:
- hWnd = windll.user32.GetForegroundWindow()
- length = windll.user32.GetWindowTextLengthW(hWnd)
- buf = create_unicode_buffer(length + 1)
- windll.user32.GetWindowTextW(hWnd, buf, length + 1)
-
- if buf.value:
- return buf.value
- else:
- return "NOTHING"
+def isAppFullScreen():
+ user32 = windll.user32
+ user32.SetProcessDPIAware()
+
+ try:
+ hWnd = user32.GetForegroundWindow()
+ rect = win32gui.GetWindowRect(hWnd)
+ return rect == (0, 0, windll.user32.GetSystemMetrics(0), windll.user32.GetSystemMetrics(1))
+ except:
+ return False
def openURL(link: str) -> None:
os.system(f"start \"\" {link}")
diff --git a/src/windows/mainWindow.py b/src/windows/mainWindow.py
index e3da2b5..13446ae 100644
--- a/src/windows/mainWindow.py
+++ b/src/windows/mainWindow.py
@@ -217,18 +217,48 @@ def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e", None))
self.closeButton.setText("")
self.minimizeButton.setText("")
+#if QT_CONFIG(tooltip)
+ self.profilesButton.setToolTip(QCoreApplication.translate("MainWindow", u"\u041f\u0440\u043e\u0444\u0438\u043b\u0438", None))
+#endif // QT_CONFIG(tooltip)
self.profilesButton.setText("")
+#if QT_CONFIG(tooltip)
+ self.settingsButton.setToolTip(QCoreApplication.translate("MainWindow", u"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438", None))
+#endif // QT_CONFIG(tooltip)
self.settingsButton.setText("")
+#if QT_CONFIG(tooltip)
+ self.adButton.setToolTip(QCoreApplication.translate("MainWindow", u"GitHub \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430", None))
+#endif // QT_CONFIG(tooltip)
self.adButton.setText("")
self.title.setText("")
self.settingsTitle.setText(QCoreApplication.translate("MainWindow", u"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438", None))
+#if QT_CONFIG(tooltip)
+ self.trayCheckbox.setToolTip(QCoreApplication.translate("MainWindow", u"\u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u0440\u0435\u0441\u0442\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f, \u0430 \u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0430\u043d\u0435\u043b\u044c \u0437\u0430\u0434\u0430\u0447.", None))
+#endif // QT_CONFIG(tooltip)
self.trayCheckbox.setText(QCoreApplication.translate("MainWindow", u"\u041f\u0440\u044f\u0442\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0442\u0440\u0435\u0439 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \"\u0417\u0430\u043a\u0440\u044b\u0442\u044c\"", None))
- self.autorunCheckbox.setText(QCoreApplication.translate("MainWindow", u"\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 (\u0430\u0432\u0442\u043e\u0437\u0430\u043f\u0443\u0441\u043a)", None))
- self.nameCheckbox.setText(QCoreApplication.translate("MainWindow", u"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u043d\u0434\u044b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 RAGE Multiplayer", None))
+#if QT_CONFIG(tooltip)
+ self.autorunCheckbox.setToolTip(QCoreApplication.translate("MainWindow", u"\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439.", None))
+#endif // QT_CONFIG(tooltip)
+ self.autorunCheckbox.setText(QCoreApplication.translate("MainWindow", u"\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 (\u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430)", None))
+#if QT_CONFIG(tooltip)
+ self.nameCheckbox.setToolTip(QCoreApplication.translate("MainWindow", u"\u041d\u0443\u0436\u043d\u043e, \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0447\u0442\u043e \u0431\u044b \u0431\u0438\u043d\u0434\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0438\u0433\u0440\u0435. \u041d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0435\u0441\u043b\u0438 \u0438\u0433\u0440\u0430 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u0430 \u0432 \u043e\u043a\u043d\u0435.", None))
+#endif // QT_CONFIG(tooltip)
+ self.nameCheckbox.setText(QCoreApplication.translate("MainWindow", u"\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u043e\u0442\u043a\u0440\u044b\u0442\u043e \u043b\u0438 \u043f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435", None))
+#if QT_CONFIG(tooltip)
+ self.createProfileButton.setToolTip(QCoreApplication.translate("MainWindow", u"\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c", None))
+#endif // QT_CONFIG(tooltip)
self.createProfileButton.setText("")
+#if QT_CONFIG(tooltip)
+ self.editProfileButton.setToolTip(QCoreApplication.translate("MainWindow", u"\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c", None))
+#endif // QT_CONFIG(tooltip)
self.editProfileButton.setText("")
+#if QT_CONFIG(tooltip)
+ self.deleteProfileButton.setToolTip(QCoreApplication.translate("MainWindow", u"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c", None))
+#endif // QT_CONFIG(tooltip)
self.deleteProfileButton.setText("")
self.profilesTitle.setText(QCoreApplication.translate("MainWindow", u"\u041f\u0440\u043e\u0444\u0438\u043b\u0438", None))
+#if QT_CONFIG(tooltip)
+ self.listWidget.setToolTip(QCoreApplication.translate("MainWindow", u"\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u0448\u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0444\u0438\u043b\u0435\u0439, \u043f\u0443\u0441\u0442\u043e \u0435\u0441\u043b\u0438 \u043d\u0435\u0442\u0443 \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u044f.", None))
+#endif // QT_CONFIG(tooltip)
self.label.setText(QCoreApplication.translate("MainWindow", u"\u0412\u0430\u0448\u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u0438:", None))
# retranslateUi
diff --git a/src/windows/profileEditWindow.py b/src/windows/profileEditWindow.py
index 555fa6f..41a8e62 100644
--- a/src/windows/profileEditWindow.py
+++ b/src/windows/profileEditWindow.py
@@ -24,7 +24,7 @@ class Ui_ProfileEditWindow(object):
def setupUi(self, ProfileEditWindow):
if not ProfileEditWindow.objectName():
ProfileEditWindow.setObjectName(u"ProfileEditWindow")
- ProfileEditWindow.resize(967, 503)
+ ProfileEditWindow.resize(967, 518)
icon = QIcon()
icon.addFile(u":/resources/logo.ico", QSize(), QIcon.Normal, QIcon.Off)
ProfileEditWindow.setWindowIcon(icon)
@@ -61,7 +61,7 @@ def setupUi(self, ProfileEditWindow):
self.centralWidget.setObjectName(u"centralWidget")
self.createProfileButton = QPushButton(self.centralWidget)
self.createProfileButton.setObjectName(u"createProfileButton")
- self.createProfileButton.setGeometry(QRect(410, 460, 181, 31))
+ self.createProfileButton.setGeometry(QRect(400, 470, 181, 31))
font = QFont()
font.setFamilies([u"Rubik"])
font.setPointSize(12)
@@ -74,7 +74,7 @@ def setupUi(self, ProfileEditWindow):
self.createProfileButton.setIconSize(QSize(18, 18))
self.shortcutlabel = QLabel(self.centralWidget)
self.shortcutlabel.setObjectName(u"shortcutlabel")
- self.shortcutlabel.setGeometry(QRect(550, 400, 91, 21))
+ self.shortcutlabel.setGeometry(QRect(540, 410, 91, 21))
font1 = QFont()
font1.setFamilies([u"Rubik"])
font1.setPointSize(14)
@@ -82,26 +82,27 @@ def setupUi(self, ProfileEditWindow):
self.shortcutlabel.setStyleSheet(u"QLabel {\n"
" color: rgb(220, 220, 220)\n"
"}")
+ self.shortcutlabel.setAlignment(Qt.AlignCenter)
self.shortcut = QKeySequenceEdit(self.centralWidget)
self.shortcut.setObjectName(u"shortcut")
- self.shortcut.setGeometry(QRect(550, 430, 91, 21))
+ self.shortcut.setGeometry(QRect(540, 440, 91, 21))
font2 = QFont()
font2.setFamilies([u"Rubik"])
font2.setPointSize(10)
self.shortcut.setFont(font2)
self.profileName = QLineEdit(self.centralWidget)
self.profileName.setObjectName(u"profileName")
- self.profileName.setGeometry(QRect(340, 430, 181, 21))
+ self.profileName.setGeometry(QRect(330, 440, 181, 21))
self.profiileNameLabel = QLabel(self.centralWidget)
self.profiileNameLabel.setObjectName(u"profiileNameLabel")
- self.profiileNameLabel.setGeometry(QRect(340, 400, 191, 20))
+ self.profiileNameLabel.setGeometry(QRect(330, 410, 191, 20))
self.profiileNameLabel.setFont(font1)
self.profiileNameLabel.setStyleSheet(u"QLabel {\n"
" color: rgb(220, 220, 220)\n"
"}")
self.verticalLayoutWidget = QWidget(self.centralWidget)
self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget")
- self.verticalLayoutWidget.setGeometry(QRect(20, 50, 921, 341))
+ self.verticalLayoutWidget.setGeometry(QRect(20, 60, 921, 341))
self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName(u"verticalLayout")
@@ -384,6 +385,16 @@ def setupUi(self, ProfileEditWindow):
font5.setFamilies([u"Rubik"])
font5.setPointSize(12)
self.title.setFont(font5)
+ self.label = QLabel(self.centralWidget)
+ self.label.setObjectName(u"label")
+ self.label.setGeometry(QRect(30, 50, 41, 16))
+ font6 = QFont()
+ font6.setPointSize(10)
+ self.label.setFont(font6)
+ self.label_2 = QLabel(self.centralWidget)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setGeometry(QRect(810, 50, 61, 16))
+ self.label_2.setFont(font6)
ProfileEditWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(ProfileEditWindow)
@@ -423,5 +434,7 @@ def retranslateUi(self, ProfileEditWindow):
self.minimizeButton.setText("")
self.closeButton.setText("")
self.title.setText(QCoreApplication.translate("ProfileEditWindow", u"\u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440", None))
+ self.label.setText(QCoreApplication.translate("ProfileEditWindow", u"\u0422\u0435\u043a\u0441\u0442", None))
+ self.label_2.setText(QCoreApplication.translate("ProfileEditWindow", u"\u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0430", None))
# retranslateUi
diff --git a/tools/build_full.bat b/tools/build.bat
similarity index 50%
rename from tools/build_full.bat
rename to tools/build.bat
index c6d2d57..c4b9408 100644
--- a/tools/build_full.bat
+++ b/tools/build.bat
@@ -1,14 +1,12 @@
@echo off
-color 7
-
mkdir build\workcache
mkdir build\runcache
mkdir build\dist
-"env\Scripts\python.exe" tools\compileUI.py
-"env\Scripts\pyinstaller.exe" --noconfirm main.spec
-"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
+call "tools\translateUI.bat"
+call "env\Scripts\pyinstaller.exe" --log-level DEBUG --noconfirm main.spec
+call "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
rd /s /q dist
rd /s /q build\main
diff --git a/tools/compileUI.py b/tools/compileUI.py
deleted file mode 100644
index 3ad02f7..0000000
--- a/tools/compileUI.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import os
-
-windowNames = [name.replace(".ui", "") for name in os.listdir("src/ui") if name.endswith("ui")]
-resourceNames = [name.replace(".qrc", "") for name in os.listdir("src/ui") if name.endswith("qrc")]
-
-for resource in resourceNames:
- os.system(f"{os.getcwd()}\\env\\Scripts\\pyside6-rcc.exe src/ui/{resource}.qrc -o src/windows/{resource}_rc.py")
- print(f"\033[92m{resource} - OK!")
-
-for window in windowNames:
- os.system(f"{os.getcwd()}\\env\\Scripts\\pyside6-uic.exe --from-imports src/ui/{window}.ui -o src/windows/{window}.py")
- print(f"\033[92m{window} - OK!")
-
-print("\033[0m")
\ No newline at end of file
diff --git a/tools/translateUI.bat b/tools/translateUI.bat
new file mode 100644
index 0000000..46d0185
--- /dev/null
+++ b/tools/translateUI.bat
@@ -0,0 +1,18 @@
+@echo off
+
+rem https://stackoverflow.com/q/138497
+rem https://stackoverflow.com/q/2048509
+
+setlocal enabledelayedexpansion
+
+for %%f in (src\ui\*.ui) do (
+ set /p val=<%%f
+ env\Scripts\pyside6-uic.exe --from-imports %%f -o src/windows/%%~nf.py
+ echo Translated: [1m[42m%%f[0m
+)
+
+for %%f in (src\ui\*.qrc) do (
+ set /p val=<%%f
+ env\Scripts\pyside6-rcc.exe %%f -o src/windows/%%~nf_rc.py
+ echo Translated: [1m[42m%%f[0m
+)
\ No newline at end of file