From 7fa360992a862fbe4daacf11a847199715c8be85 Mon Sep 17 00:00:00 2001
From: Samuel T
Date: Tue, 9 Nov 2021 17:47:07 -0800
Subject: [PATCH 1/8] Livesplit integration (#60)
* Added LiveSplit Integration
Single Source of truth for version number
* Fixed freeze on close by using killable QThreads and an os.kill signal
Also added the icon to the build command
Co-authored-by: KaDiWa4
---
requirements.txt | 2 +-
res/about.ui | 2 +-
src/AutoSplit.py | 257 ++++++++++++++++++++++++++++---------------
src/about.py | 3 +-
src/menu_bar.py | 11 +-
src/settings_file.py | 7 +-
6 files changed, 183 insertions(+), 99 deletions(-)
diff --git a/requirements.txt b/requirements.txt
index b9c87383..249bcf65 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@
#
# Usage: pip install -r requirements.txt
#
-# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F src\AutoSplit.py
+# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F --icon=src\icon.ico src\AutoSplit.py
#
# You can find other wheels here: https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyqt4
# If you use 32-bit installation of Python, use the the 2nd URL instead.
diff --git a/res/about.ui b/res/about.ui
index d247f2c3..f6fe56a6 100644
--- a/res/about.ui
+++ b/res/about.ui
@@ -65,7 +65,7 @@
- Version: 1.2.0
+ Version:
diff --git a/src/AutoSplit.py b/src/AutoSplit.py
index daed4516..16a10401 100644
--- a/src/AutoSplit.py
+++ b/src/AutoSplit.py
@@ -1,5 +1,7 @@
from PyQt4 import QtGui, QtCore, QtTest
+from menu_bar import about, VERSION, viewHelp
import sys
+import signal
import os
import win32gui
import cv2
@@ -7,16 +9,17 @@
import ctypes.wintypes
import ctypes
import keyboard
-import glob
+import threading
import numpy as np
import design
-import about
import compare
import capture_windows
import split_parser
+
class AutoSplit(QtGui.QMainWindow, design.Ui_MainWindow):
+ # Importing the functions inside of the class will make them methods of the class
from hotkeys import beforeSettingHotkey, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey, setPauseHotkey
from error_messages import (splitImageDirectoryError, splitImageDirectoryNotFoundError, imageTypeError, regionError, regionSizeError,
splitHotkeyError, customThresholdError, customPauseError, alphaChannelError, alignRegionImageTypeError, alignmentNotMatchedError,
@@ -24,7 +27,6 @@ class AutoSplit(QtGui.QMainWindow, design.Ui_MainWindow):
invalidSettingsError, oldVersionSettingsFileError, noSettingsFileOnOpenError, tooManySettingsFilesOnOpenError)
from settings_file import saveSettings, saveSettingsAs, loadSettings, haveSettingsChanged, getSaveSettingsValues
from screen_region import selectRegion, selectWindow, alignRegion
- from menu_bar import about, viewHelp
myappid = u'mycompany.myproduct.subproduct.version'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
@@ -42,9 +44,12 @@ def __init__(self, parent=None):
super(AutoSplit, self).__init__(parent)
self.setupUi(self)
+ # Parse command line args
+ self.is_auto_controlled = ('--auto-controlled' in sys.argv)
+
# close all processes when closing window
- self.actionView_Help.triggered.connect(self.viewHelp)
- self.actionAbout.triggered.connect(self.about)
+ self.actionView_Help.triggered.connect(viewHelp)
+ self.actionAbout.triggered.connect(lambda: about(self))
self.actionSave_Settings.triggered.connect(self.saveSettings)
self.actionSave_Settings_As.triggered.connect(self.saveSettingsAs)
self.actionLoad_Settings.triggered.connect(self.loadSettings)
@@ -54,6 +59,57 @@ def __init__(self, parent=None):
self.skipsplitButton.setEnabled(False)
self.resetButton.setEnabled(False)
+ if self.is_auto_controlled:
+ self.setsplithotkeyButton.setEnabled(False)
+ self.setresethotkeyButton.setEnabled(False)
+ self.setskipsplithotkeyButton.setEnabled(False)
+ self.setundosplithotkeyButton.setEnabled(False)
+ self.setpausehotkeyButton.setEnabled(False)
+ self.startautosplitterButton.setEnabled(False)
+ self.splitLineEdit.setEnabled(False)
+ self.resetLineEdit.setEnabled(False)
+ self.skipsplitLineEdit.setEnabled(False)
+ self.undosplitLineEdit.setEnabled(False)
+ self.pausehotkeyLineEdit.setEnabled(False)
+
+ # Send version and process ID to stdout
+ print(f"{VERSION}\n{os.getpid()}", flush=True)
+
+ class Worker(QtCore.QObject):
+ autosplit = None
+
+ def __init__(self, autosplit):
+ self.autosplit = autosplit
+ super().__init__()
+
+ def run(self):
+ while True:
+ line = input()
+ # TODO: "AutoSplit Integration" needs to call this and wait instead of outright killing the app.
+ # TODO: See if we can also get LiveSplit to wait on Exit in "AutoSplit Integration"
+ # For now this can only used in a Development environment
+ if line == 'kill':
+ self.autosplit.closeEvent()
+ break
+ elif line == 'start':
+ self.autosplit.startAutoSplitter()
+ elif line == 'split' or line == 'skip':
+ self.autosplit.startSkipSplit()
+ elif line == 'undo':
+ self.autosplit.startUndoSplit()
+ elif line == 'reset':
+ self.autosplit.startReset()
+ # TODO: Not yet implemented in AutoSplit Integration
+ # elif line == 'pause':
+ # self.startPause()
+
+ # Use and Start the thread that checks for updates from LiveSplit
+ self.update_auto_control = QtCore.QThread()
+ worker = Worker(self)
+ worker.moveToThread(self.update_auto_control)
+ self.update_auto_control.started.connect(worker.run)
+ self.update_auto_control.start()
+
# resize to these width and height so that FPS performance increases
self.RESIZE_WIDTH = 320
self.RESIZE_HEIGHT = 240
@@ -118,6 +174,7 @@ def __init__(self, parent=None):
self.live_image_function_on_open = True
# FUNCTIONS
+
#TODO add checkbox for going back to image 1 when resetting.
def browse(self):
# User selects the file with the split images in it.
@@ -283,7 +340,7 @@ def checkFPS(self):
# undo split button and hotkey connect to here
def undoSplit(self):
- if self.undosplitButton.isEnabled() == False:
+ if self.undosplitButton.isEnabled() == False and self.is_auto_controlled == False:
return
if self.loop_number != 1 and self.groupDummySplitsCheckBox.isChecked() == False:
@@ -306,7 +363,7 @@ def undoSplit(self):
# skip split button and hotkey connect to here
def skipSplit(self):
- if self.skipsplitButton.isEnabled() == False:
+ if self.skipsplitButton.isEnabled() == False and self.is_auto_controlled == False:
return
if self.loop_number < self.split_image_loop_amount[self.split_image_number] and self.groupDummySplitsCheckBox.isChecked() == False:
@@ -335,10 +392,10 @@ def reset(self):
# functions for the hotkeys to return to the main thread from signals and start their corresponding functions
def startAutoSplitter(self):
# if the auto splitter is already running or the button is disabled, don't emit the signal to start it.
- if self.startautosplitterButton.text() == 'Running..' or self.startautosplitterButton.isEnabled() == False:
+ if self.startautosplitterButton.text() == 'Running..' or \
+ (self.startautosplitterButton.isEnabled() == False and self.is_auto_controlled == False):
return
- else:
- self.startAutoSplitterSignal.emit()
+ self.startAutoSplitterSignal.emit()
def startReset(self):
self.resetSignal.emit()
@@ -402,7 +459,7 @@ def autoSplitter(self):
return
#error out if there is a {p} flag but no pause hotkey set.
- if self.pausehotkeyLineEdit.text() == '' and split_parser.flags_from_filename(image) & 0x08 == 0x08:
+ if self.pausehotkeyLineEdit.text() == '' and split_parser.flags_from_filename(image) & 0x08 == 0x08 and self.is_auto_controlled == False:
self.guiChangesOnReset()
self.pauseHotkeyError()
return
@@ -421,7 +478,7 @@ def autoSplitter(self):
self.customThresholdError(image)
return
- if self.splitLineEdit.text() == '':
+ if self.splitLineEdit.text() == '' and self.is_auto_controlled == False:
self.guiChangesOnReset()
self.splitHotkeyError()
return
@@ -444,7 +501,7 @@ def autoSplitter(self):
return
# If there is no reset hotkey set but a reset image is present, throw an error.
- if self.resetLineEdit.text() == '' and self.reset_image is not None:
+ if self.resetLineEdit.text() == '' and self.reset_image is not None and self.is_auto_controlled == False:
self.guiChangesOnReset()
self.resetHotkeyError()
return
@@ -530,7 +587,10 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- keyboard.send(str(self.resetLineEdit.text()))
+ if self.is_auto_controlled:
+ print("reset", flush = True)
+ else:
+ keyboard.send(str(self.resetLineEdit.text()))
self.reset()
# loop goes into here if start auto splitter text is "Start Auto Splitter"
@@ -566,17 +626,18 @@ def autoSplitter(self):
else:
self.highestsimilarityLabel.setText(' ')
- # if its the last split image and last loop number, disable the skip split button
- if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
- self.skipsplitButton.setEnabled(False)
- else:
- self.skipsplitButton.setEnabled(True)
+ if self.is_auto_controlled == False:
+ # if its the last split image and last loop number, disable the skip split button
+ if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
+ self.skipsplitButton.setEnabled(False)
+ else:
+ self.skipsplitButton.setEnabled(True)
- # if its the first split image and first loop, disable the undo split button
- if self.split_image_number == 0 and self.loop_number == 1:
- self.undosplitButton.setEnabled(False)
- else:
- self.undosplitButton.setEnabled(True)
+ # if its the first split image and first loop, disable the undo split button
+ if self.split_image_number == 0 and self.loop_number == 1:
+ self.undosplitButton.setEnabled(False)
+ else:
+ self.undosplitButton.setEnabled(True)
# if the b flag is set, let similarity go above threshold first, then split on similarity below threshold.
# if no b flag, just split when similarity goes above threshold.
@@ -637,7 +698,10 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- keyboard.send(str(self.resetLineEdit.text()))
+ if self.is_auto_controlled:
+ print("reset", flush = True)
+ else:
+ keyboard.send(str(self.resetLineEdit.text()))
self.reset()
continue
@@ -647,9 +711,15 @@ def autoSplitter(self):
# if {p} flag hit pause key, otherwise hit split hotkey
if (self.flags & 0x08 == 0x08):
- keyboard.send(str(self.pausehotkeyLineEdit.text()))
+ if self.is_auto_controlled:
+ print("pause", flush = True)
+ else:
+ keyboard.send(str(self.pausehotkeyLineEdit.text()))
else:
- keyboard.send(str(self.splitLineEdit.text()))
+ if self.is_auto_controlled:
+ print("split", flush = True)
+ else:
+ keyboard.send(str(self.splitLineEdit.text()))
# increase loop number if needed, set to 1 if it was the last loop.
if self.loop_number < self.split_image_loop_amount[self.split_image_number]:
@@ -678,17 +748,18 @@ def autoSplitter(self):
self.currentSplitImage.setAlignment(QtCore.Qt.AlignCenter)
self.imageloopLabel.setText('Image Loop #: -')
- # if its the last split image and last loop number, disable the skip split button
- if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
- self.skipsplitButton.setEnabled(False)
- else:
- self.skipsplitButton.setEnabled(True)
+ if self.is_auto_controlled == False:
+ # if its the last split image and last loop number, disable the skip split button
+ if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
+ self.skipsplitButton.setEnabled(False)
+ else:
+ self.skipsplitButton.setEnabled(True)
- # if its the first split image and first loop, disable the undo split button
- if self.split_image_number == 0 and self.loop_number == 1:
- self.undosplitButton.setEnabled(False)
- else:
- self.undosplitButton.setEnabled(True)
+ # if its the first split image and first loop, disable the undo split button
+ if self.split_image_number == 0 and self.loop_number == 1:
+ self.undosplitButton.setEnabled(False)
+ else:
+ self.undosplitButton.setEnabled(True)
QtGui.QApplication.processEvents()
@@ -733,18 +804,21 @@ def autoSplitter(self):
def guiChangesOnStart(self):
self.startautosplitterButton.setText('Running..')
self.browseButton.setEnabled(False)
- self.startautosplitterButton.setEnabled(False)
- self.resetButton.setEnabled(True)
- self.undosplitButton.setEnabled(True)
- self.skipsplitButton.setEnabled(True)
- self.setsplithotkeyButton.setEnabled(False)
- self.setresethotkeyButton.setEnabled(False)
- self.setskipsplithotkeyButton.setEnabled(False)
- self.setundosplithotkeyButton.setEnabled(False)
- self.setpausehotkeyButton.setEnabled(False)
self.custompausetimesCheckBox.setEnabled(False)
self.customthresholdsCheckBox.setEnabled(False)
self.groupDummySplitsCheckBox.setEnabled(False)
+
+ if self.is_auto_controlled == False:
+ self.startautosplitterButton.setEnabled(False)
+ self.resetButton.setEnabled(True)
+ self.undosplitButton.setEnabled(True)
+ self.skipsplitButton.setEnabled(True)
+ self.setsplithotkeyButton.setEnabled(False)
+ self.setresethotkeyButton.setEnabled(False)
+ self.setskipsplithotkeyButton.setEnabled(False)
+ self.setundosplithotkeyButton.setEnabled(False)
+ self.setpausehotkeyButton.setEnabled(False)
+
QtGui.QApplication.processEvents()
def guiChangesOnReset(self):
@@ -755,18 +829,21 @@ def guiChangesOnReset(self):
self.livesimilarityLabel.setText(' ')
self.highestsimilarityLabel.setText(' ')
self.browseButton.setEnabled(True)
- self.startautosplitterButton.setEnabled(True)
- self.resetButton.setEnabled(False)
- self.undosplitButton.setEnabled(False)
- self.skipsplitButton.setEnabled(False)
- self.setsplithotkeyButton.setEnabled(True)
- self.setresethotkeyButton.setEnabled(True)
- self.setskipsplithotkeyButton.setEnabled(True)
- self.setundosplithotkeyButton.setEnabled(True)
- self.setpausehotkeyButton.setEnabled(True)
self.custompausetimesCheckBox.setEnabled(True)
self.customthresholdsCheckBox.setEnabled(True)
self.groupDummySplitsCheckBox.setEnabled(True)
+
+ if self.is_auto_controlled == False:
+ self.startautosplitterButton.setEnabled(True)
+ self.resetButton.setEnabled(False)
+ self.undosplitButton.setEnabled(False)
+ self.skipsplitButton.setEnabled(False)
+ self.setsplithotkeyButton.setEnabled(True)
+ self.setresethotkeyButton.setEnabled(True)
+ self.setskipsplithotkeyButton.setEnabled(True)
+ self.setundosplithotkeyButton.setEnabled(True)
+ self.setpausehotkeyButton.setEnabled(True)
+
QtGui.QApplication.processEvents()
def compareImage(self, image, mask, capture):
@@ -920,41 +997,43 @@ def updateSplitImage(self):
self.highest_similarity = 0.001
# exit safely when closing the window
- def closeEvent(self, event):
- if self.haveSettingsChanged():
- #give a different warning if there was never a settings file that was loaded successfully, and save as instead of save.
- if self.last_successfully_loaded_settings_file_path == None:
- msgBox = QtGui.QMessageBox
- warning = msgBox.warning(self, "AutoSplit","Do you want to save changes made to settings file Untitled?", msgBox.Yes | msgBox.No | msgBox.Cancel)
- if warning == msgBox.Yes:
- self.saveSettingsAs()
- sys.exit()
- event.accept()
- if warning == msgBox.No:
- event.accept()
- sys.exit()
- pass
- if warning == msgBox.Cancel:
- event.ignore()
- return
- else:
- msgBox = QtGui.QMessageBox
- warning = msgBox.warning(self, "AutoSplit", "Do you want to save the changes made to the settings file " + os.path.basename(self.last_successfully_loaded_settings_file_path) + " ?", msgBox.Yes | msgBox.No | msgBox.Cancel)
- if warning == msgBox.Yes:
- self.saveSettings()
- sys.exit()
- event.accept()
- if warning == msgBox.No:
- event.accept()
- sys.exit()
- pass
- if warning == msgBox.Cancel:
- event.ignore()
- return
- else:
- event.accept()
+ def closeEvent(self, event=None):
+ def exit():
+ if event is not None:
+ event.accept()
+ if self.is_auto_controlled:
+ self.update_auto_control.terminate()
+ # stop main thread (which is probably blocked reading input) via an interrupt signal
+ # only available for windows in version 3.2 or higher
+ os.kill(os.getpid(), signal.SIGINT)
sys.exit()
+ # Simulates LiveSplit quitting without asking. See "TODO" at update_auto_control Worker
+ # This also more gracefully exits LiveSplit
+ # Users can still manually save their settings
+ if event is None:
+ exit()
+
+ if self.haveSettingsChanged():
+ # give a different warning if there was never a settings file that was loaded successfully, and save as instead of save.
+ msgBox = QtGui.QMessageBox
+ settings_file_name = "Untitled" \
+ if self.last_successfully_loaded_settings_file_path is None \
+ else os.path.basename(self.last_successfully_loaded_settings_file_path)
+ warning_message = f"Do you want to save changes made to settings file {settings_file_name}?"
+
+ warning = msgBox.warning(self, "AutoSplit", warning_message, msgBox.Yes | msgBox.No | msgBox.Cancel)
+
+ if warning == msgBox.Yes:
+ # TODO: Don't close if user cancelled the save
+ self.saveSettingsAs()
+ exit()
+ if warning == msgBox.No:
+ exit()
+ if warning == msgBox.Cancel:
+ event.ignore()
+ else:
+ exit()
def main():
@@ -967,4 +1046,4 @@ def main():
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
diff --git a/src/about.py b/src/about.py
index 93f90bfe..4dd6b430 100644
--- a/src/about.py
+++ b/src/about.py
@@ -59,7 +59,7 @@ def retranslateUi(self, aboutAutoSplitWidget):
aboutAutoSplitWidget.setWindowTitle(_translate("aboutAutoSplitWidget", "About AutoSplit", None))
self.okButton.setText(_translate("aboutAutoSplitWidget", "OK", None))
self.createdbyLabel.setText(_translate("aboutAutoSplitWidget", "Created by Toufool and Faschz
", None))
- self.versionLabel.setText(_translate("aboutAutoSplitWidget", "Version: 1.5.1", None))
+ self.versionLabel.setText(_translate("aboutAutoSplitWidget", "Version: ", None))
self.donatetextLabel.setText(_translate("aboutAutoSplitWidget", "If you enjoy using this program, please\n"
" consider donating. Thank you!", None))
self.donatebuttonLabel.setText(_translate("aboutAutoSplitWidget", "
", None))
@@ -75,4 +75,3 @@ def retranslateUi(self, aboutAutoSplitWidget):
ui.setupUi(aboutAutoSplitWidget)
aboutAutoSplitWidget.show()
sys.exit(app.exec_())
-
diff --git a/src/menu_bar.py b/src/menu_bar.py
index 598f8435..9cd18e5b 100644
--- a/src/menu_bar.py
+++ b/src/menu_bar.py
@@ -2,6 +2,10 @@
from PyQt4 import QtGui
import about
+# AutoSplit Version number
+VERSION = "1.5.0"
+
+
# About Window
class AboutWidget(QtGui.QWidget, about.Ui_aboutAutoSplitWidget):
def __init__(self):
@@ -9,11 +13,12 @@ def __init__(self):
self.setupUi(self)
self.createdbyLabel.setOpenExternalLinks(True)
self.donatebuttonLabel.setOpenExternalLinks(True)
+ self.versionLabel.setText(f"Version: {VERSION}")
self.show()
-def viewHelp(self):
- os.system("start \"\" https://github.com/Toufool/Auto-Split#tutorial")
- return
+
+def viewHelp():
+ os.system("start \"\" https://github.com/Toufool/Auto-Split/blob/master/README.md#tutorial")
def about(self):
diff --git a/src/settings_file.py b/src/settings_file.py
index 6e7e270d..3304858c 100644
--- a/src/settings_file.py
+++ b/src/settings_file.py
@@ -197,9 +197,10 @@ def loadSettings(self):
keyboard.remove_hotkey(self.split_hotkey)
except AttributeError:
pass
- self.splitLineEdit.setText(str(self.split_key))
- self.split_hotkey = keyboard.add_hotkey(str(self.split_key), self.startAutoSplitter)
- self.old_split_key = self.split_key
+ if self.is_auto_controlled == False:
+ self.splitLineEdit.setText(str(self.split_key))
+ self.split_hotkey = keyboard.add_hotkey(str(self.split_key), self.startAutoSplitter)
+ self.old_split_key = self.split_key
# pass if the key is an empty string (hotkey was never set)
except ValueError:
pass
From b2e93d7ad7bf19ed323d4ab07c3452bcc1912c12 Mon Sep 17 00:00:00 2001
From: Austin <37423484+Toufool@users.noreply.github.com>
Date: Tue, 9 Nov 2021 21:00:41 -0500
Subject: [PATCH 2/8] Revert "Livesplit integration (#60)" (#76)
This reverts commit 7fa360992a862fbe4daacf11a847199715c8be85.
---
requirements.txt | 2 +-
res/about.ui | 2 +-
src/AutoSplit.py | 257 +++++++++++++++----------------------------
src/about.py | 3 +-
src/menu_bar.py | 11 +-
src/settings_file.py | 7 +-
6 files changed, 99 insertions(+), 183 deletions(-)
diff --git a/requirements.txt b/requirements.txt
index 249bcf65..b9c87383 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@
#
# Usage: pip install -r requirements.txt
#
-# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F --icon=src\icon.ico src\AutoSplit.py
+# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F src\AutoSplit.py
#
# You can find other wheels here: https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyqt4
# If you use 32-bit installation of Python, use the the 2nd URL instead.
diff --git a/res/about.ui b/res/about.ui
index f6fe56a6..d247f2c3 100644
--- a/res/about.ui
+++ b/res/about.ui
@@ -65,7 +65,7 @@
- Version:
+ Version: 1.2.0
diff --git a/src/AutoSplit.py b/src/AutoSplit.py
index 16a10401..daed4516 100644
--- a/src/AutoSplit.py
+++ b/src/AutoSplit.py
@@ -1,7 +1,5 @@
from PyQt4 import QtGui, QtCore, QtTest
-from menu_bar import about, VERSION, viewHelp
import sys
-import signal
import os
import win32gui
import cv2
@@ -9,17 +7,16 @@
import ctypes.wintypes
import ctypes
import keyboard
-import threading
+import glob
import numpy as np
import design
+import about
import compare
import capture_windows
import split_parser
-
class AutoSplit(QtGui.QMainWindow, design.Ui_MainWindow):
- # Importing the functions inside of the class will make them methods of the class
from hotkeys import beforeSettingHotkey, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey, setPauseHotkey
from error_messages import (splitImageDirectoryError, splitImageDirectoryNotFoundError, imageTypeError, regionError, regionSizeError,
splitHotkeyError, customThresholdError, customPauseError, alphaChannelError, alignRegionImageTypeError, alignmentNotMatchedError,
@@ -27,6 +24,7 @@ class AutoSplit(QtGui.QMainWindow, design.Ui_MainWindow):
invalidSettingsError, oldVersionSettingsFileError, noSettingsFileOnOpenError, tooManySettingsFilesOnOpenError)
from settings_file import saveSettings, saveSettingsAs, loadSettings, haveSettingsChanged, getSaveSettingsValues
from screen_region import selectRegion, selectWindow, alignRegion
+ from menu_bar import about, viewHelp
myappid = u'mycompany.myproduct.subproduct.version'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
@@ -44,12 +42,9 @@ def __init__(self, parent=None):
super(AutoSplit, self).__init__(parent)
self.setupUi(self)
- # Parse command line args
- self.is_auto_controlled = ('--auto-controlled' in sys.argv)
-
# close all processes when closing window
- self.actionView_Help.triggered.connect(viewHelp)
- self.actionAbout.triggered.connect(lambda: about(self))
+ self.actionView_Help.triggered.connect(self.viewHelp)
+ self.actionAbout.triggered.connect(self.about)
self.actionSave_Settings.triggered.connect(self.saveSettings)
self.actionSave_Settings_As.triggered.connect(self.saveSettingsAs)
self.actionLoad_Settings.triggered.connect(self.loadSettings)
@@ -59,57 +54,6 @@ def __init__(self, parent=None):
self.skipsplitButton.setEnabled(False)
self.resetButton.setEnabled(False)
- if self.is_auto_controlled:
- self.setsplithotkeyButton.setEnabled(False)
- self.setresethotkeyButton.setEnabled(False)
- self.setskipsplithotkeyButton.setEnabled(False)
- self.setundosplithotkeyButton.setEnabled(False)
- self.setpausehotkeyButton.setEnabled(False)
- self.startautosplitterButton.setEnabled(False)
- self.splitLineEdit.setEnabled(False)
- self.resetLineEdit.setEnabled(False)
- self.skipsplitLineEdit.setEnabled(False)
- self.undosplitLineEdit.setEnabled(False)
- self.pausehotkeyLineEdit.setEnabled(False)
-
- # Send version and process ID to stdout
- print(f"{VERSION}\n{os.getpid()}", flush=True)
-
- class Worker(QtCore.QObject):
- autosplit = None
-
- def __init__(self, autosplit):
- self.autosplit = autosplit
- super().__init__()
-
- def run(self):
- while True:
- line = input()
- # TODO: "AutoSplit Integration" needs to call this and wait instead of outright killing the app.
- # TODO: See if we can also get LiveSplit to wait on Exit in "AutoSplit Integration"
- # For now this can only used in a Development environment
- if line == 'kill':
- self.autosplit.closeEvent()
- break
- elif line == 'start':
- self.autosplit.startAutoSplitter()
- elif line == 'split' or line == 'skip':
- self.autosplit.startSkipSplit()
- elif line == 'undo':
- self.autosplit.startUndoSplit()
- elif line == 'reset':
- self.autosplit.startReset()
- # TODO: Not yet implemented in AutoSplit Integration
- # elif line == 'pause':
- # self.startPause()
-
- # Use and Start the thread that checks for updates from LiveSplit
- self.update_auto_control = QtCore.QThread()
- worker = Worker(self)
- worker.moveToThread(self.update_auto_control)
- self.update_auto_control.started.connect(worker.run)
- self.update_auto_control.start()
-
# resize to these width and height so that FPS performance increases
self.RESIZE_WIDTH = 320
self.RESIZE_HEIGHT = 240
@@ -174,7 +118,6 @@ def run(self):
self.live_image_function_on_open = True
# FUNCTIONS
-
#TODO add checkbox for going back to image 1 when resetting.
def browse(self):
# User selects the file with the split images in it.
@@ -340,7 +283,7 @@ def checkFPS(self):
# undo split button and hotkey connect to here
def undoSplit(self):
- if self.undosplitButton.isEnabled() == False and self.is_auto_controlled == False:
+ if self.undosplitButton.isEnabled() == False:
return
if self.loop_number != 1 and self.groupDummySplitsCheckBox.isChecked() == False:
@@ -363,7 +306,7 @@ def undoSplit(self):
# skip split button and hotkey connect to here
def skipSplit(self):
- if self.skipsplitButton.isEnabled() == False and self.is_auto_controlled == False:
+ if self.skipsplitButton.isEnabled() == False:
return
if self.loop_number < self.split_image_loop_amount[self.split_image_number] and self.groupDummySplitsCheckBox.isChecked() == False:
@@ -392,10 +335,10 @@ def reset(self):
# functions for the hotkeys to return to the main thread from signals and start their corresponding functions
def startAutoSplitter(self):
# if the auto splitter is already running or the button is disabled, don't emit the signal to start it.
- if self.startautosplitterButton.text() == 'Running..' or \
- (self.startautosplitterButton.isEnabled() == False and self.is_auto_controlled == False):
+ if self.startautosplitterButton.text() == 'Running..' or self.startautosplitterButton.isEnabled() == False:
return
- self.startAutoSplitterSignal.emit()
+ else:
+ self.startAutoSplitterSignal.emit()
def startReset(self):
self.resetSignal.emit()
@@ -459,7 +402,7 @@ def autoSplitter(self):
return
#error out if there is a {p} flag but no pause hotkey set.
- if self.pausehotkeyLineEdit.text() == '' and split_parser.flags_from_filename(image) & 0x08 == 0x08 and self.is_auto_controlled == False:
+ if self.pausehotkeyLineEdit.text() == '' and split_parser.flags_from_filename(image) & 0x08 == 0x08:
self.guiChangesOnReset()
self.pauseHotkeyError()
return
@@ -478,7 +421,7 @@ def autoSplitter(self):
self.customThresholdError(image)
return
- if self.splitLineEdit.text() == '' and self.is_auto_controlled == False:
+ if self.splitLineEdit.text() == '':
self.guiChangesOnReset()
self.splitHotkeyError()
return
@@ -501,7 +444,7 @@ def autoSplitter(self):
return
# If there is no reset hotkey set but a reset image is present, throw an error.
- if self.resetLineEdit.text() == '' and self.reset_image is not None and self.is_auto_controlled == False:
+ if self.resetLineEdit.text() == '' and self.reset_image is not None:
self.guiChangesOnReset()
self.resetHotkeyError()
return
@@ -587,10 +530,7 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- if self.is_auto_controlled:
- print("reset", flush = True)
- else:
- keyboard.send(str(self.resetLineEdit.text()))
+ keyboard.send(str(self.resetLineEdit.text()))
self.reset()
# loop goes into here if start auto splitter text is "Start Auto Splitter"
@@ -626,18 +566,17 @@ def autoSplitter(self):
else:
self.highestsimilarityLabel.setText(' ')
- if self.is_auto_controlled == False:
- # if its the last split image and last loop number, disable the skip split button
- if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
- self.skipsplitButton.setEnabled(False)
- else:
- self.skipsplitButton.setEnabled(True)
+ # if its the last split image and last loop number, disable the skip split button
+ if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
+ self.skipsplitButton.setEnabled(False)
+ else:
+ self.skipsplitButton.setEnabled(True)
- # if its the first split image and first loop, disable the undo split button
- if self.split_image_number == 0 and self.loop_number == 1:
- self.undosplitButton.setEnabled(False)
- else:
- self.undosplitButton.setEnabled(True)
+ # if its the first split image and first loop, disable the undo split button
+ if self.split_image_number == 0 and self.loop_number == 1:
+ self.undosplitButton.setEnabled(False)
+ else:
+ self.undosplitButton.setEnabled(True)
# if the b flag is set, let similarity go above threshold first, then split on similarity below threshold.
# if no b flag, just split when similarity goes above threshold.
@@ -698,10 +637,7 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- if self.is_auto_controlled:
- print("reset", flush = True)
- else:
- keyboard.send(str(self.resetLineEdit.text()))
+ keyboard.send(str(self.resetLineEdit.text()))
self.reset()
continue
@@ -711,15 +647,9 @@ def autoSplitter(self):
# if {p} flag hit pause key, otherwise hit split hotkey
if (self.flags & 0x08 == 0x08):
- if self.is_auto_controlled:
- print("pause", flush = True)
- else:
- keyboard.send(str(self.pausehotkeyLineEdit.text()))
+ keyboard.send(str(self.pausehotkeyLineEdit.text()))
else:
- if self.is_auto_controlled:
- print("split", flush = True)
- else:
- keyboard.send(str(self.splitLineEdit.text()))
+ keyboard.send(str(self.splitLineEdit.text()))
# increase loop number if needed, set to 1 if it was the last loop.
if self.loop_number < self.split_image_loop_amount[self.split_image_number]:
@@ -748,18 +678,17 @@ def autoSplitter(self):
self.currentSplitImage.setAlignment(QtCore.Qt.AlignCenter)
self.imageloopLabel.setText('Image Loop #: -')
- if self.is_auto_controlled == False:
- # if its the last split image and last loop number, disable the skip split button
- if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
- self.skipsplitButton.setEnabled(False)
- else:
- self.skipsplitButton.setEnabled(True)
+ # if its the last split image and last loop number, disable the skip split button
+ if (self.split_image_number == self.number_of_split_images - 1 and self.loop_number == self.split_image_loop_amount[self.split_image_number]) or (self.groupDummySplitsCheckBox.isChecked() == True and self.dummy_splits_array[self.split_image_number:].count(False) <= 1):
+ self.skipsplitButton.setEnabled(False)
+ else:
+ self.skipsplitButton.setEnabled(True)
- # if its the first split image and first loop, disable the undo split button
- if self.split_image_number == 0 and self.loop_number == 1:
- self.undosplitButton.setEnabled(False)
- else:
- self.undosplitButton.setEnabled(True)
+ # if its the first split image and first loop, disable the undo split button
+ if self.split_image_number == 0 and self.loop_number == 1:
+ self.undosplitButton.setEnabled(False)
+ else:
+ self.undosplitButton.setEnabled(True)
QtGui.QApplication.processEvents()
@@ -804,21 +733,18 @@ def autoSplitter(self):
def guiChangesOnStart(self):
self.startautosplitterButton.setText('Running..')
self.browseButton.setEnabled(False)
+ self.startautosplitterButton.setEnabled(False)
+ self.resetButton.setEnabled(True)
+ self.undosplitButton.setEnabled(True)
+ self.skipsplitButton.setEnabled(True)
+ self.setsplithotkeyButton.setEnabled(False)
+ self.setresethotkeyButton.setEnabled(False)
+ self.setskipsplithotkeyButton.setEnabled(False)
+ self.setundosplithotkeyButton.setEnabled(False)
+ self.setpausehotkeyButton.setEnabled(False)
self.custompausetimesCheckBox.setEnabled(False)
self.customthresholdsCheckBox.setEnabled(False)
self.groupDummySplitsCheckBox.setEnabled(False)
-
- if self.is_auto_controlled == False:
- self.startautosplitterButton.setEnabled(False)
- self.resetButton.setEnabled(True)
- self.undosplitButton.setEnabled(True)
- self.skipsplitButton.setEnabled(True)
- self.setsplithotkeyButton.setEnabled(False)
- self.setresethotkeyButton.setEnabled(False)
- self.setskipsplithotkeyButton.setEnabled(False)
- self.setundosplithotkeyButton.setEnabled(False)
- self.setpausehotkeyButton.setEnabled(False)
-
QtGui.QApplication.processEvents()
def guiChangesOnReset(self):
@@ -829,21 +755,18 @@ def guiChangesOnReset(self):
self.livesimilarityLabel.setText(' ')
self.highestsimilarityLabel.setText(' ')
self.browseButton.setEnabled(True)
+ self.startautosplitterButton.setEnabled(True)
+ self.resetButton.setEnabled(False)
+ self.undosplitButton.setEnabled(False)
+ self.skipsplitButton.setEnabled(False)
+ self.setsplithotkeyButton.setEnabled(True)
+ self.setresethotkeyButton.setEnabled(True)
+ self.setskipsplithotkeyButton.setEnabled(True)
+ self.setundosplithotkeyButton.setEnabled(True)
+ self.setpausehotkeyButton.setEnabled(True)
self.custompausetimesCheckBox.setEnabled(True)
self.customthresholdsCheckBox.setEnabled(True)
self.groupDummySplitsCheckBox.setEnabled(True)
-
- if self.is_auto_controlled == False:
- self.startautosplitterButton.setEnabled(True)
- self.resetButton.setEnabled(False)
- self.undosplitButton.setEnabled(False)
- self.skipsplitButton.setEnabled(False)
- self.setsplithotkeyButton.setEnabled(True)
- self.setresethotkeyButton.setEnabled(True)
- self.setskipsplithotkeyButton.setEnabled(True)
- self.setundosplithotkeyButton.setEnabled(True)
- self.setpausehotkeyButton.setEnabled(True)
-
QtGui.QApplication.processEvents()
def compareImage(self, image, mask, capture):
@@ -997,43 +920,41 @@ def updateSplitImage(self):
self.highest_similarity = 0.001
# exit safely when closing the window
- def closeEvent(self, event=None):
- def exit():
- if event is not None:
- event.accept()
- if self.is_auto_controlled:
- self.update_auto_control.terminate()
- # stop main thread (which is probably blocked reading input) via an interrupt signal
- # only available for windows in version 3.2 or higher
- os.kill(os.getpid(), signal.SIGINT)
- sys.exit()
-
- # Simulates LiveSplit quitting without asking. See "TODO" at update_auto_control Worker
- # This also more gracefully exits LiveSplit
- # Users can still manually save their settings
- if event is None:
- exit()
-
+ def closeEvent(self, event):
if self.haveSettingsChanged():
- # give a different warning if there was never a settings file that was loaded successfully, and save as instead of save.
- msgBox = QtGui.QMessageBox
- settings_file_name = "Untitled" \
- if self.last_successfully_loaded_settings_file_path is None \
- else os.path.basename(self.last_successfully_loaded_settings_file_path)
- warning_message = f"Do you want to save changes made to settings file {settings_file_name}?"
-
- warning = msgBox.warning(self, "AutoSplit", warning_message, msgBox.Yes | msgBox.No | msgBox.Cancel)
-
- if warning == msgBox.Yes:
- # TODO: Don't close if user cancelled the save
- self.saveSettingsAs()
- exit()
- if warning == msgBox.No:
- exit()
- if warning == msgBox.Cancel:
- event.ignore()
+ #give a different warning if there was never a settings file that was loaded successfully, and save as instead of save.
+ if self.last_successfully_loaded_settings_file_path == None:
+ msgBox = QtGui.QMessageBox
+ warning = msgBox.warning(self, "AutoSplit","Do you want to save changes made to settings file Untitled?", msgBox.Yes | msgBox.No | msgBox.Cancel)
+ if warning == msgBox.Yes:
+ self.saveSettingsAs()
+ sys.exit()
+ event.accept()
+ if warning == msgBox.No:
+ event.accept()
+ sys.exit()
+ pass
+ if warning == msgBox.Cancel:
+ event.ignore()
+ return
+ else:
+ msgBox = QtGui.QMessageBox
+ warning = msgBox.warning(self, "AutoSplit", "Do you want to save the changes made to the settings file " + os.path.basename(self.last_successfully_loaded_settings_file_path) + " ?", msgBox.Yes | msgBox.No | msgBox.Cancel)
+ if warning == msgBox.Yes:
+ self.saveSettings()
+ sys.exit()
+ event.accept()
+ if warning == msgBox.No:
+ event.accept()
+ sys.exit()
+ pass
+ if warning == msgBox.Cancel:
+ event.ignore()
+ return
else:
- exit()
+ event.accept()
+ sys.exit()
+
def main():
@@ -1046,4 +967,4 @@ def main():
if __name__ == '__main__':
- main()
+ main()
\ No newline at end of file
diff --git a/src/about.py b/src/about.py
index 4dd6b430..93f90bfe 100644
--- a/src/about.py
+++ b/src/about.py
@@ -59,7 +59,7 @@ def retranslateUi(self, aboutAutoSplitWidget):
aboutAutoSplitWidget.setWindowTitle(_translate("aboutAutoSplitWidget", "About AutoSplit", None))
self.okButton.setText(_translate("aboutAutoSplitWidget", "OK", None))
self.createdbyLabel.setText(_translate("aboutAutoSplitWidget", "Created by Toufool and Faschz
", None))
- self.versionLabel.setText(_translate("aboutAutoSplitWidget", "Version: ", None))
+ self.versionLabel.setText(_translate("aboutAutoSplitWidget", "Version: 1.5.1", None))
self.donatetextLabel.setText(_translate("aboutAutoSplitWidget", "If you enjoy using this program, please\n"
" consider donating. Thank you!", None))
self.donatebuttonLabel.setText(_translate("aboutAutoSplitWidget", "

", None))
@@ -75,3 +75,4 @@ def retranslateUi(self, aboutAutoSplitWidget):
ui.setupUi(aboutAutoSplitWidget)
aboutAutoSplitWidget.show()
sys.exit(app.exec_())
+
diff --git a/src/menu_bar.py b/src/menu_bar.py
index 9cd18e5b..598f8435 100644
--- a/src/menu_bar.py
+++ b/src/menu_bar.py
@@ -2,10 +2,6 @@
from PyQt4 import QtGui
import about
-# AutoSplit Version number
-VERSION = "1.5.0"
-
-
# About Window
class AboutWidget(QtGui.QWidget, about.Ui_aboutAutoSplitWidget):
def __init__(self):
@@ -13,12 +9,11 @@ def __init__(self):
self.setupUi(self)
self.createdbyLabel.setOpenExternalLinks(True)
self.donatebuttonLabel.setOpenExternalLinks(True)
- self.versionLabel.setText(f"Version: {VERSION}")
self.show()
-
-def viewHelp():
- os.system("start \"\" https://github.com/Toufool/Auto-Split/blob/master/README.md#tutorial")
+def viewHelp(self):
+ os.system("start \"\" https://github.com/Toufool/Auto-Split#tutorial")
+ return
def about(self):
diff --git a/src/settings_file.py b/src/settings_file.py
index 3304858c..6e7e270d 100644
--- a/src/settings_file.py
+++ b/src/settings_file.py
@@ -197,10 +197,9 @@ def loadSettings(self):
keyboard.remove_hotkey(self.split_hotkey)
except AttributeError:
pass
- if self.is_auto_controlled == False:
- self.splitLineEdit.setText(str(self.split_key))
- self.split_hotkey = keyboard.add_hotkey(str(self.split_key), self.startAutoSplitter)
- self.old_split_key = self.split_key
+ self.splitLineEdit.setText(str(self.split_key))
+ self.split_hotkey = keyboard.add_hotkey(str(self.split_key), self.startAutoSplitter)
+ self.old_split_key = self.split_key
# pass if the key is an empty string (hotkey was never set)
except ValueError:
pass
From 4d52774e4e3bd64fae46c1385052f8fefc925ee5 Mon Sep 17 00:00:00 2001
From: Samuel T
Date: Tue, 9 Nov 2021 18:18:10 -0800
Subject: [PATCH 3/8] Fix numpad hotkey (#61)
* Fixed numpad hotkeys
- Differentiate between numpad and regular numbers
- Differentiate between numpad actions and regular actions
- Differentiate between numpad actions and numpad numbers
- Differentiate dot, numpad dot (or decimal), and delete
- Delete and numapd delete won't be cross-compatible if localized in non-english
- Used hooks and simplified code
* Fix loading settings with incomplete hotkey configuration
* Added Build requirements
* Actually send the right event for numpad keys using pyautogui
Co-authored-by: KaDiWa4
---
.vscode/extensions.json | 10 +-
.vscode/settings.json | 11 +-
README.md | 3 +
requirements.txt | 1 +
src/AutoSplit.py | 17 ++-
src/hotkeys.py | 309 ++++++++++++++++++++--------------------
src/settings_file.py | 119 +++++++---------
7 files changed, 234 insertions(+), 236 deletions(-)
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 0254035d..ca9b77ca 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,8 +1,14 @@
{
"recommendations": [
- "ms-pyright.pyright",
+ "ms-python.vscode-pylance",
"ms-python.python",
"sonarsource.sonarlint-vscode",
- "davidanson.vscode-markdownlint"
+ "davidanson.vscode-markdownlint",
+ "shardulm94.trailing-spaces",
+ "eamodio.gitlens"
+ ],
+ "unwantedRecommendations": [
+ "ms-pyright.pyright",
+ "esbenp.prettier-vscode"
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index c9c340c1..977842be 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -26,13 +26,13 @@
120,
]
},
- "//1": "Keeping autoformat to false for now to keep minimal changes",
+ // Keeping autoformat to false for now to keep minimal changes
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": false,
},
"python.linting.pylintEnabled": false,
- "//2": "Using flake8 as other linters are incomplete or have too many false positives last I tried",
+ // Using flake8 as other linters are incomplete or have too many false positives last I tried
"python.linting.flake8Enabled": true,
"python.linting.enabled": true,
"python.linting.pycodestyleEnabled": false,
@@ -43,6 +43,11 @@
"python.formatting.autopep8Args": [
"--max-line-length=120"
],
- "python.pythonPath": "",
"files.insertFinalNewline": true,
+ "trailing-spaces.deleteModifiedLinesOnly": true,
+ "trailing-spaces.includeEmptyLines": true,
+ "trailing-spaces.trimOnSave": true,
+ "trailing-spaces.syntaxIgnore": [
+ "markdown"
+ ]
}
diff --git a/README.md b/README.md
index 2c54f4dc..473df18d 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,9 @@ This program compares split images to a capture region of any window (OBS, xspli
### Compatability
- Windows 7, 10, and 11
+### Building
+- Read [requirements.txt](/requirements.txt) for information on how to run/build the python code
+
### Opening the program
- Download the [latest version](https://github.com/austinryan/Auto-Split/releases)
- Extract the file and open AutoSplit.exe.
diff --git a/requirements.txt b/requirements.txt
index b9c87383..dc467e0b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -20,3 +20,4 @@ Pillow
ImageHash
pywin32
keyboard
+pyautogui
diff --git a/src/AutoSplit.py b/src/AutoSplit.py
index daed4516..c4a1b45c 100644
--- a/src/AutoSplit.py
+++ b/src/AutoSplit.py
@@ -6,16 +6,15 @@
import time
import ctypes.wintypes
import ctypes
-import keyboard
-import glob
import numpy as np
+from hotkeys import send_hotkey
import design
-import about
import compare
import capture_windows
import split_parser
+
class AutoSplit(QtGui.QMainWindow, design.Ui_MainWindow):
from hotkeys import beforeSettingHotkey, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey, setPauseHotkey
from error_messages import (splitImageDirectoryError, splitImageDirectoryNotFoundError, imageTypeError, regionError, regionSizeError,
@@ -530,7 +529,7 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- keyboard.send(str(self.resetLineEdit.text()))
+ send_hotkey(self.resetLineEdit.text())
self.reset()
# loop goes into here if start auto splitter text is "Start Auto Splitter"
@@ -637,7 +636,7 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- keyboard.send(str(self.resetLineEdit.text()))
+ send_hotkey(self.resetLineEdit.text())
self.reset()
continue
@@ -647,9 +646,9 @@ def autoSplitter(self):
# if {p} flag hit pause key, otherwise hit split hotkey
if (self.flags & 0x08 == 0x08):
- keyboard.send(str(self.pausehotkeyLineEdit.text()))
+ send_hotkey(self.pausehotkeyLineEdit.text())
else:
- keyboard.send(str(self.splitLineEdit.text()))
+ send_hotkey(self.splitLineEdit.text())
# increase loop number if needed, set to 1 if it was the last loop.
if self.loop_number < self.split_image_loop_amount[self.split_image_number]:
@@ -721,7 +720,7 @@ def autoSplitter(self):
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
- keyboard.send(str(self.resetLineEdit.text()))
+ send_hotkey(self.resetLineEdit.text())
self.reset()
continue
@@ -967,4 +966,4 @@ def main():
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
diff --git a/src/hotkeys.py b/src/hotkeys.py
index eca9a822..9465bdc8 100644
--- a/src/hotkeys.py
+++ b/src/hotkeys.py
@@ -1,5 +1,9 @@
import keyboard
+import pyautogui
import threading
+# While not usually recommended, we don't manipulate the mouse, and we don't want the extra delay
+pyautogui.FAILSAFE = False
+
# do all of these after you click "set hotkey" but before you type the hotkey.
def beforeSettingHotkey(self):
@@ -26,10 +30,88 @@ def afterSettingHotkey(self):
self.setundosplithotkeyButton.setEnabled(True)
self.setpausehotkeyButton.setEnabled(True)
- return
-#--------------------HOTKEYS--------------------------
-#Going to comment on one func, and others will be similar.
+def is_digit(key):
+ try:
+ key_as_num = int(key)
+ return key_as_num >= 0 and key_as_num <= 9
+ except Exception:
+ return False
+
+
+# Supports sending the appropriate scan code for all the special cases
+def send_hotkey(key_or_scan_code):
+ hotkey_type = type(key_or_scan_code)
+
+ # Deal with regular inputs
+ if hotkey_type is int:
+ return keyboard.send(key_or_scan_code)
+ elif hotkey_type is not str:
+ raise TypeError(f'key_or_scan_code "{key_or_scan_code}" {hotkey_type} should be an int or str')
+ if (not (key_or_scan_code.startswith('num ') or key_or_scan_code == 'decimal')):
+ return keyboard.send(key_or_scan_code)
+
+ # Deal with problematic keys. Even by sending specific scan code 'keyboard' still sends the defautl (wrong) key
+ # keyboard.send(keyboard.key_to_scan_codes(key_or_scan_code)[1])
+ pyautogui.hotkey(key_or_scan_code.replace(' ', ''))
+
+
+def __validate_keypad(expected_key, keyboard_event):
+ # Prevent "(keypad)delete", "(keypad)./decimal" and "del" from triggering each other
+ # as well as "." and "(keypad)./decimal"
+ if keyboard_event.scan_code == 83 or keyboard_event.scan_code == 52:
+ if expected_key == keyboard_event.name:
+ return True
+ else:
+ # TODO: "del" won't work with "(keypad)delete" if localized in non-english (ie: "suppr" in french)
+ return False
+ # Prevent "action keys" from triggering "keypad keys"
+ if is_digit(keyboard_event.name[-1]):
+ # Prevent "regular numbers" from activating "keypad numbers"
+ if expected_key.startswith("num "):
+ return keyboard_event.is_keypad
+ # Prevent "keypad numbers" from activating "regular numbers"
+ else:
+ return not keyboard_event.is_keypad
+ else:
+ # Prevent "keypad action keys" from triggering "regular numbers" and "keypad numbers"
+ # Still allow the same key that might be localized differently on keypad vs non-keypad
+ return not is_digit(expected_key[-1])
+
+
+# NOTE: This is a workaround very specific to numpads.
+# Windows reports different physical keys with the same scan code.
+# For example, "Home", "Num Home" and "Num 7" are all "71".
+# See: https://github.com/boppreh/keyboard/issues/171#issuecomment-390437684
+#
+# We're doing the check here instead of saving the key code because it'll
+# cause issues with save files and the non-keypad shared keys are localized
+# while the keypad ones aren't.
+#
+# Since we reuse the key string we set to send to LiveSplit, we can't use fake names like "num home".
+# We're also trying to achieve the same hotkey behaviour as LiveSplit has.
+def _hotkey_action(keyboard_event, key_name, action):
+ if keyboard_event.event_type == keyboard.KEY_DOWN and __validate_keypad(key_name, keyboard_event):
+ action()
+
+
+def __get_key_name(keyboard_event):
+ return f"num {keyboard_event.name}" \
+ if keyboard_event.is_keypad and is_digit(keyboard_event.name) \
+ else keyboard_event.name
+
+
+def __is_key_already_set(self, key_name):
+ return key_name == self.splitLineEdit.text() \
+ or key_name == self.resetLineEdit.text() \
+ or key_name == self.skipsplitLineEdit.text() \
+ or key_name == self.undosplitLineEdit.text() \
+ or key_name == self.pausehotkeyLineEdit.text()
+
+
+# --------------------HOTKEYS--------------------------
+# TODO: Refactor to de-duplicate all this code, including settings_file.py
+# Going to comment on one func, and others will be similar.
def setSplitHotkey(self):
self.setsplithotkeyButton.setText('Press a key..')
@@ -38,48 +120,34 @@ def setSplitHotkey(self):
# new thread points to callback. this thread is needed or GUI will freeze
# while the program waits for user input on the hotkey
- def callback():
+ def callback(hotkey):
# try to remove the previously set hotkey if there is one.
try:
- keyboard.remove_hotkey(self.split_hotkey)
- except AttributeError:
- pass
- #this error was coming up when loading the program and
- #the lineEdit area was empty (no hotkey set), then you
- #set one, reload the setting once back to blank works,
- #but if you click reload settings again, it errors
- #we can just have it pass, but don't want to throw in
- #generic exception here in case another one of these
- #pops up somewhere.
- except KeyError:
+ keyboard.unhook_key(hotkey)
+ # KeyError was coming up when loading the program and
+ # the lineEdit area was empty (no hotkey set), then you
+ # set one, reload the setting once back to blank works,
+ # but if you click reload settings again, it errors
+ # we can just have it pass, but don't want to throw in
+ # generic exception here in case another one of these
+ # pops up somewhere.
+ except (AttributeError, KeyError):
pass
# wait until user presses the hotkey, then keyboard module reads the input
- self.split_key = keyboard.read_hotkey(False)
-
- # If the key the user presses is equal to itself or another hotkey already set,
- # this causes issues. so here, it catches that, and will make no changes to the hotkey.
+ key_name = __get_key_name(keyboard.read_event(True))
try:
- if self.split_key == self.splitLineEdit.text() \
- or self.split_key == self.resetLineEdit.text() \
- or self.split_key == self.skipsplitLineEdit.text() \
- or self.split_key == self.undosplitLineEdit.text() \
- or self.split_key == self.pausehotkeyLineEdit.text():
- self.split_hotkey = keyboard.add_hotkey(self.old_split_key, self.startAutoSplitter)
- self.afterSettingHotkeySignal.emit()
- return
- except AttributeError:
- self.afterSettingHotkeySignal.emit()
- return
+ # If the key the user presses is equal to itself or another hotkey already set,
+ # this causes issues. so here, it catches that, and will make no changes to the hotkey.
- # keyboard module allows you to hit multiple keys for a hotkey. they are joined
- # together by +. If user hits two keys at the same time, make no changes to the
- # hotkey. A try and except is needed if a hotkey hasn't been set yet. I'm not
- # allowing for these multiple-key hotkeys because it can cause crashes, and
- # not many people are going to really use or need this.
- try:
- if '+' in self.split_key:
- self.split_hotkey = keyboard.add_hotkey(self.old_split_key, self.startAutoSplitter)
+ # or
+
+ # keyboard module allows you to hit multiple keys for a hotkey. they are joined
+ # together by +. If user hits two keys at the same time, make no changes to the
+ # hotkey. A try and except is needed if a hotkey hasn't been set yet. I'm not
+ # allowing for these multiple-key hotkeys because it can cause crashes, and
+ # not many people are going to really use or need this.
+ if __is_key_already_set(self, key_name) or '+' in key_name:
self.afterSettingHotkeySignal.emit()
return
except AttributeError:
@@ -88,192 +156,131 @@ def callback():
# add the key as the hotkey, set the text into the LineEdit, set it as old_xxx_key,
# then emite a signal to re-enable some buttons and change some text in GUI.
- self.split_hotkey = keyboard.add_hotkey(self.split_key, self.startAutoSplitter)
- self.splitLineEdit.setText(self.split_key)
- self.old_split_key = self.split_key
+
+ # We need to inspect the event to know if it comes from numpad because of _canonial_names.
+ # See: https://github.com/boppreh/keyboard/issues/161#issuecomment-386825737
+ # The best way to achieve this is make our own hotkey handling on top of hook
+ # See: https://github.com/boppreh/keyboard/issues/216#issuecomment-431999553
+ self.split_hotkey = keyboard.hook_key(key_name, lambda e: _hotkey_action(e, key_name, self.startAutoSplitter))
+ self.splitLineEdit.setText(key_name)
+ self.split_key = key_name
self.afterSettingHotkeySignal.emit()
- return
- t = threading.Thread(target=callback)
+ t = threading.Thread(target=callback, args=(self.split_hotkey,))
t.start()
- return
+
def setResetHotkey(self):
self.setresethotkeyButton.setText('Press a key..')
self.beforeSettingHotkey()
- def callback():
+ def callback(hotkey):
try:
- keyboard.remove_hotkey(self.reset_hotkey)
- except AttributeError:
+ keyboard.unhook_key(hotkey)
+ except (AttributeError, KeyError):
pass
- except KeyError:
- pass
- self.reset_key = keyboard.read_hotkey(False)
- try:
- if self.reset_key == self.splitLineEdit.text() \
- or self.reset_key == self.resetLineEdit.text() \
- or self.reset_key == self.skipsplitLineEdit.text() \
- or self.reset_key == self.undosplitLineEdit.text() \
- or self.reset_key == self.pausehotkeyLineEdit.text():
- self.reset_hotkey = keyboard.add_hotkey(self.old_reset_key, self.startReset)
- self.afterSettingHotkeySignal.emit()
- return
- except AttributeError:
- self.afterSettingHotkeySignal.emit()
- return
+
+ key_name = __get_key_name(keyboard.read_event(True))
+
try:
- if '+' in self.reset_key:
- self.reset_hotkey = keyboard.add_hotkey(self.old_reset_key, self.startReset)
+ if __is_key_already_set(self, key_name) or '+' in key_name:
self.afterSettingHotkeySignal.emit()
return
except AttributeError:
self.afterSettingHotkeySignal.emit()
return
- self.reset_hotkey = keyboard.add_hotkey(self.reset_key, self.startReset)
- self.resetLineEdit.setText(self.reset_key)
- self.old_reset_key = self.reset_key
+
+ self.reset_hotkey = keyboard.hook_key(key_name, lambda e: _hotkey_action(e, key_name, self.startReset))
+ self.resetLineEdit.setText(key_name)
+ self.reset_key = key_name
self.afterSettingHotkeySignal.emit()
- return
- t = threading.Thread(target=callback)
+ t = threading.Thread(target=callback, args=(self.reset_hotkey,))
t.start()
- return
+
def setSkipSplitHotkey(self):
self.setskipsplithotkeyButton.setText('Press a key..')
self.beforeSettingHotkey()
- def callback():
+ def callback(hotkey):
try:
- keyboard.remove_hotkey(self.skip_split_hotkey)
- except AttributeError:
- pass
- except KeyError:
+ keyboard.unhook_key(hotkey)
+ except (AttributeError, KeyError):
pass
- self.skip_split_key = keyboard.read_hotkey(False)
+ key_name = __get_key_name(keyboard.read_event(True))
try:
- if self.skip_split_key == self.splitLineEdit.text() \
- or self.skip_split_key == self.resetLineEdit.text() \
- or self.skip_split_key == self.skipsplitLineEdit.text() \
- or self.skip_split_key == self.undosplitLineEdit.text() \
- or self.skip_split_key == self.pausehotkeyLineEdit.text():
- self.skip_split_hotkey = keyboard.add_hotkey(self.old_skip_split_key, self.startSkipSplit)
+ if __is_key_already_set(self, key_name) or '+' in key_name:
self.afterSettingHotkeySignal.emit()
return
except AttributeError:
self.afterSettingHotkeySignal.emit()
return
- try:
- if '+' in self.skip_split_key:
- self.skip_split_hotkey = keyboard.add_hotkey(self.old_skip_split_key, self.startSkipSplit)
- self.afterSettingHotkeySignal.emit()
- return
- except AttributeError:
- self.afterSettingHotkeySignal.emit()
- return
-
- self.skip_split_hotkey = keyboard.add_hotkey(self.skip_split_key, self.startSkipSplit)
- self.skipsplitLineEdit.setText(self.skip_split_key)
- self.old_skip_split_key = self.skip_split_key
+ self.skip_split_hotkey = keyboard.hook_key(key_name, lambda e: _hotkey_action(e, key_name, self.startSkipSplit))
+ self.skipsplitLineEdit.setText(key_name)
+ self.skip_split_key = key_name
self.afterSettingHotkeySignal.emit()
- return
- t = threading.Thread(target=callback)
+ t = threading.Thread(target=callback, args=(self.skip_split_hotkey,))
t.start()
- return
+
def setUndoSplitHotkey(self):
self.setundosplithotkeyButton.setText('Press a key..')
self.beforeSettingHotkey()
- def callback():
+ def callback(hotkey):
try:
- keyboard.remove_hotkey(self.undo_split_hotkey)
- except AttributeError:
- pass
- except KeyError:
+ keyboard.unhook_key(hotkey)
+ except (AttributeError, KeyError):
pass
- self.undo_split_key = keyboard.read_hotkey(False)
+ key_name = __get_key_name(keyboard.read_event(True))
try:
- if self.undo_split_key == self.splitLineEdit.text() \
- or self.undo_split_key == self.resetLineEdit.text() \
- or self.undo_split_key == self.skipsplitLineEdit.text() \
- or self.undo_split_key == self.undosplitLineEdit.text() \
- or self.undo_split_key == self.pausehotkeyLineEdit.text():
- self.undo_split_hotkey = keyboard.add_hotkey(self.old_undo_split_key, self.startUndoSplit)
+ if __is_key_already_set(self, key_name) or '+' in key_name:
self.afterSettingHotkeySignal.emit()
return
except AttributeError:
self.afterSettingHotkeySignal.emit()
return
- try:
- if '+' in self.undo_split_key:
- self.undo_split_hotkey = keyboard.add_hotkey(self.old_undo_split_key, self.startUndoSplit)
- self.afterSettingHotkeySignal.emit()
- return
- except AttributeError:
- self.afterSettingHotkeySignal.emit()
- return
-
- self.undo_split_hotkey = keyboard.add_hotkey(self.undo_split_key, self.startUndoSplit)
- self.undosplitLineEdit.setText(self.undo_split_key)
- self.old_undo_split_key = self.undo_split_key
+ self.undo_split_hotkey = keyboard.hook_key(key_name, lambda e: _hotkey_action(e, key_name, self.startUndoSplit))
+ self.undosplitLineEdit.setText(key_name)
+ self.undo_split_key = key_name
self.afterSettingHotkeySignal.emit()
- return
- t = threading.Thread(target=callback)
+ t = threading.Thread(target=callback, args=(self.undo_split_hotkey,))
t.start()
- return
+
def setPauseHotkey(self):
self.setpausehotkeyButton.setText('Press a key..')
self.beforeSettingHotkey()
- def callback():
+ def callback(hotkey):
try:
- keyboard.remove_hotkey(self.pause_hotkey)
- except AttributeError:
- pass
- except KeyError:
+ keyboard.unhook_key(hotkey)
+ except (AttributeError, KeyError):
pass
- self.pause_key = keyboard.read_hotkey(False)
-
- try:
- if self.pause_key == self.splitLineEdit.text() \
- or self.pause_key == self.resetLineEdit.text() \
- or self.pause_key == self.skipsplitLineEdit.text() \
- or self.pause_key == self.undosplitLineEdit.text() \
- or self.pause_key == self.pausehotkeyLineEdit.text():
- self.pause_hotkey = keyboard.add_hotkey(self.old_pause_key, self.startPause)
- self.afterSettingHotkeySignal.emit()
- return
- except AttributeError:
- self.afterSettingHotkeySignal.emit()
- return
+ key_name = __get_key_name(keyboard.read_event(True))
try:
- if '+' in self.pause_key:
- self.pause_hotkey = keyboard.add_hotkey(self.old_pause_key, self.startPause)
+ if __is_key_already_set(self, key_name) or '+' in key_name:
self.afterSettingHotkeySignal.emit()
return
except AttributeError:
self.afterSettingHotkeySignal.emit()
return
- self.pause_hotkey = keyboard.add_hotkey(self.pause_key, self.startPause)
- self.pausehotkeyLineEdit.setText(self.pause_key)
- self.old_pause_key = self.pause_key
+ self.pause_hotkey = keyboard.hook_key(key_name, lambda e: _hotkey_action(e, key_name, self.startPause))
+ self.pausehotkeyLineEdit.setText(key_name)
+ self.pause_key = key_name
self.afterSettingHotkeySignal.emit()
- return
- t = threading.Thread(target=callback)
+ t = threading.Thread(target=callback, args=(self.pause_hotkey,))
t.start()
- return
\ No newline at end of file
diff --git a/src/settings_file.py b/src/settings_file.py
index 6e7e270d..9f352cb7 100644
--- a/src/settings_file.py
+++ b/src/settings_file.py
@@ -2,7 +2,10 @@
import win32gui
import pickle
import glob
+import logging
from PyQt4 import QtGui
+from hotkeys import _hotkey_action
+
def getSaveSettingsValues(self):
# get values to be able to save settings
@@ -106,7 +109,14 @@ def saveSettingsAs(self):
def loadSettings(self):
- if self.load_settings_on_open == True:
+ # hotkeys need to be initialized to be passed as thread arguments in hotkeys.py
+ self.split_hotkey = ""
+ self.reset_hotkey = ""
+ self.skip_split_hotkey = ""
+ self.undo_split_hotkey = ""
+ self.pause_hotkey = ""
+
+ if self.load_settings_on_open:
self.settings_files = glob.glob("*.pkl")
if len(self.settings_files) < 1:
self.noSettingsFileOnOpenError()
@@ -166,101 +176,68 @@ def loadSettings(self):
self.hwnd = win32gui.FindWindow(None, self.hwnd_title)
# set custom checkbox's accordingly
- if self.custom_pause_times_setting == 1:
- self.custompausetimesCheckBox.setChecked(True)
- else:
- self.custompausetimesCheckBox.setChecked(False)
-
- if self.custom_thresholds_setting == 1:
- self.customthresholdsCheckBox.setChecked(True)
- else:
- self.customthresholdsCheckBox.setChecked(False)
-
- if self.group_dummy_splits_undo_skip_setting == 1:
- self.groupDummySplitsCheckBox.setChecked(True)
- else:
- self.groupDummySplitsCheckBox.setChecked(False)
-
- if self.loop_setting == 1:
- self.loopCheckBox.setChecked(True)
- else:
- self.loopCheckBox.setChecked(False)
-
- if self.auto_start_on_reset_setting == 1:
- self.autostartonresetCheckBox.setChecked(True)
- else:
- self.autostartonresetCheckBox.setChecked(False)
+ self.custompausetimesCheckBox.setChecked(self.custom_pause_times_setting == 1)
+ self.customthresholdsCheckBox.setChecked(self.custom_thresholds_setting == 1)
+ self.groupDummySplitsCheckBox.setChecked(self.group_dummy_splits_undo_skip_setting == 1)
+ self.loopCheckBox.setChecked(self.loop_setting == 1)
+ self.autostartonresetCheckBox.setChecked(self.auto_start_on_reset_setting == 1)
+ # TODO: Reuse code from hotkeys rather than duplicating here
# try to set hotkeys from when user last closed the window
try:
- try:
- keyboard.remove_hotkey(self.split_hotkey)
- except AttributeError:
- pass
+ keyboard.unhook_key(self.split_hotkey)
+ except (AttributeError, KeyError):
+ pass
+ try:
self.splitLineEdit.setText(str(self.split_key))
- self.split_hotkey = keyboard.add_hotkey(str(self.split_key), self.startAutoSplitter)
- self.old_split_key = self.split_key
+ self.split_hotkey = keyboard.hook_key(str(self.split_key), lambda e: _hotkey_action(e, self.split_key, self.startAutoSplitter))
# pass if the key is an empty string (hotkey was never set)
- except ValueError:
- pass
- except KeyError:
+ except (ValueError, KeyError):
pass
try:
- try:
- keyboard.remove_hotkey(self.reset_hotkey)
- except AttributeError:
- pass
- self.resetLineEdit.setText(str(self.reset_key))
- self.reset_hotkey = keyboard.add_hotkey(str(self.reset_key), self.startReset)
- self.old_reset_key = self.reset_key
- except ValueError:
+ keyboard.unhook_key(self.reset_hotkey)
+ except (AttributeError, KeyError):
pass
- except KeyError:
+ try:
+ self.resetLineEdit.setText(self.reset_key)
+ self.reset_hotkey = keyboard.hook_key(self.reset_key, lambda e: _hotkey_action(e, self.reset_key, self.startReset))
+ except (ValueError, KeyError):
pass
try:
- try:
- keyboard.remove_hotkey(self.skip_split_hotkey)
- except AttributeError:
- pass
- self.skipsplitLineEdit.setText(str(self.skip_split_key))
- self.skip_split_hotkey = keyboard.add_hotkey(str(self.skip_split_key), self.startSkipSplit)
- self.old_skip_split_key = self.skip_split_key
- except ValueError:
+ keyboard.unhook_key(self.skip_split_hotkey)
+ except (AttributeError, KeyError):
pass
- except KeyError:
+ try:
+ self.skipsplitLineEdit.setText(self.skip_split_key)
+ self.skip_split_hotkey = keyboard.hook_key(self.skip_split_key, lambda e: _hotkey_action(e, self.skip_split_key, self.startSkipSplit))
+ except (ValueError, KeyError):
pass
try:
- try:
- keyboard.remove_hotkey(self.undo_split_hotkey)
- except AttributeError:
- pass
- self.undosplitLineEdit.setText(str(self.undo_split_key))
- self.undo_split_hotkey = keyboard.add_hotkey(str(self.undo_split_key), self.startUndoSplit)
- self.old_undo_split_key = self.undo_split_key
- except ValueError:
+ keyboard.unhook_key(self.undo_split_hotkey)
+ except (AttributeError, KeyError):
pass
- except KeyError:
+ try:
+ self.undosplitLineEdit.setText(self.undo_split_key)
+ self.undo_split_hotkey = keyboard.hook_key(self.undo_split_key, lambda e: _hotkey_action(e, self.undo_split_key, self.startUndoSplit))
+ except (ValueError, KeyError):
pass
try:
- try:
- keyboard.remove_hotkey(self.pause_hotkey)
- except AttributeError:
- pass
- self.pausehotkeyLineEdit.setText(str(self.pause_key))
- self.pause_hotkey = keyboard.add_hotkey(str(self.pause_key), self.startPause)
- self.old_pause_key = self.pause_key
- except ValueError:
+ keyboard.unhook_key(self.pause_hotkey)
+ except (AttributeError, KeyError):
pass
- except KeyError:
+ try:
+ self.pausehotkeyLineEdit.setText(self.pause_key)
+ self.pause_hotkey = keyboard.hook_key(self.pause_key, lambda e: _hotkey_action(e, self.pause_key, self.startPause))
+ except (ValueError, KeyError):
pass
self.last_successfully_loaded_settings_file_path = self.load_settings_file_path
self.checkLiveImage()
except Exception:
+ logging.error(logging.traceback.format_exc())
self.invalidSettingsError()
- pass
From faf2bf38f189c1ce766bf4c33c5bb86f7bfe89be Mon Sep 17 00:00:00 2001
From: Samuel T
Date: Tue, 9 Nov 2021 18:25:49 -0800
Subject: [PATCH 4/8] Parameter auto detected (#67)
* Treeshold, pause and mask can be detected in file without app config
Remove remaining of the check box
Prevent default value to be override
Author: Moliman
* Autodetect parameters:
- Get masked from transparency
- Remove masked flag
- Changed "custom" threshold and pause time to "default threshold and pause time
* Added basic config files
Including vscode IDE configs
* Added Build requirements
* Fix libraries version
Co-authored-by: Moliman
Co-authored-by: KaDiWa4
Co-authored-by: Austin <37423484+Toufool@users.noreply.github.com>
---
requirements.txt | 14 +--
res/design.ui | 68 ++------------
src/AutoSplit.py | 203 +++++++++++++++--------------------------
src/AutoSplit.spec | 34 +++++++
src/capture_windows.py | 1 +
src/compare.py | 31 ++++---
src/design.py | 32 ++-----
src/error_messages.py | 37 +-------
src/screen_region.py | 9 +-
src/settings_file.py | 174 ++++++++++++++++++++++++-----------
src/split_parser.py | 12 +--
11 files changed, 278 insertions(+), 337 deletions(-)
create mode 100644 src/AutoSplit.spec
diff --git a/requirements.txt b/requirements.txt
index dc467e0b..a6af9ffc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,14 +2,16 @@
#
# Python: CPython 3.7 (not 3.8 as there is no cp38 wheel for PyQt4)
#
-# Usage: pip install -r requirements.txt
+# Usage: pip3.7 install -r requirements.txt
#
-# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F src\AutoSplit.py
+# If you're having issues with the libraries, you might want to first run:
+# pip3.7 uninstall -r requirements.txt
+#
+# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F --hidden-import sip --icon=src\icon.ico src\AutoSplit.py
#
# You can find other wheels here: https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyqt4
-# If you use 32-bit installation of Python, use the the 2nd URL instead.
-https://download.lfd.uci.edu/pythonlibs/w4tscw6k/PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
-# https://download.lfd.uci.edu/pythonlibs/w4tscw6k/PyQt4-4.11.4-cp37-cp37m-win32.whl
+https://download.lfd.uci.edu/pythonlibs/q4trcu4l/PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
+# https://download.lfd.uci.edu/pythonlibs/q4trcu4l/PyQt4-4.11.4-cp37-cp37m-win32.whl
#
# Comment this out if you don't want to create AutoSplit.exe:
PyInstaller
@@ -18,6 +20,6 @@ PyInstaller
opencv-python
Pillow
ImageHash
-pywin32
+pywin32==226
keyboard
pyautogui
diff --git a/res/design.ui b/res/design.ui
index 72e473cf..8c54b027 100644
--- a/res/design.ui
+++ b/res/design.ui
@@ -141,11 +141,12 @@
10
378
91
- 16
+ 21
- Similarity threshold
+ Similarity threshold
+Default value
@@ -237,11 +238,12 @@
10
420
111
- 16
+ 21
- Pause time (seconds)
+ Pause time (seconds)
+Default value
@@ -748,7 +750,7 @@
430
50
- 101
+ 221
16
@@ -1029,56 +1031,6 @@
10.000000000000000
-
-
- true
-
-
-
- 10
- 435
- 121
- 17
-
-
-
-
-
-
- Custom pause times
-
-
- false
-
-
- false
-
-
-
-
- true
-
-
-
- 10
- 394
- 111
- 17
-
-
-
-
-
-
- Custom thresholds
-
-
- false
-
-
- false
-
-
@@ -1113,7 +1065,7 @@
252
443
- 230
+ 240
17
@@ -1302,8 +1254,6 @@
yLabel
comparisonmethodComboBox
pauseDoubleSpinBox
- custompausetimesCheckBox
- customthresholdsCheckBox
comparisonmethodLabel
alignregionButton
groupDummySplitsCheckBox
@@ -1389,9 +1339,7 @@
comparisonmethodComboBox
showlivesimilarityCheckBox
showhighestsimilarityCheckBox
- customthresholdsCheckBox
similaritythresholdDoubleSpinBox
- custompausetimesCheckBox
pauseDoubleSpinBox
splitLineEdit
resetLineEdit
diff --git a/src/AutoSplit.py b/src/AutoSplit.py
index c4a1b45c..bd627b71 100644
--- a/src/AutoSplit.py
+++ b/src/AutoSplit.py
@@ -1,31 +1,34 @@
+#!/usr/bin/python3.7
+# -*- coding: utf-8 -*-
+
from PyQt4 import QtGui, QtCore, QtTest
+from menu_bar import about, viewHelp
+from win32 import win32gui
import sys
import os
-import win32gui
import cv2
import time
import ctypes.wintypes
import ctypes
import numpy as np
-
from hotkeys import send_hotkey
import design
import compare
import capture_windows
import split_parser
-
-class AutoSplit(QtGui.QMainWindow, design.Ui_MainWindow):
- from hotkeys import beforeSettingHotkey, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey, setPauseHotkey
- from error_messages import (splitImageDirectoryError, splitImageDirectoryNotFoundError, imageTypeError, regionError, regionSizeError,
- splitHotkeyError, customThresholdError, customPauseError, alphaChannelError, alignRegionImageTypeError, alignmentNotMatchedError,
- multipleResetImagesError, noResetImageThresholdError, resetHotkeyError, pauseHotkeyError, dummySplitsError, settingsNotFoundError,
- invalidSettingsError, oldVersionSettingsFileError, noSettingsFileOnOpenError, tooManySettingsFilesOnOpenError)
- from settings_file import saveSettings, saveSettingsAs, loadSettings, haveSettingsChanged, getSaveSettingsValues
- from screen_region import selectRegion, selectWindow, alignRegion
- from menu_bar import about, viewHelp
-
- myappid = u'mycompany.myproduct.subproduct.version'
+class AutoSplit(QtWidgets.QMainWindow, design.Ui_MainWindow):
+ from compare import checkIfImageHasTransparency
+ from error_messages import (
+ splitImageDirectoryError, splitImageDirectoryNotFoundError, imageTypeError, regionError, regionSizeError,
+ splitHotkeyError, alignRegionImageTypeError, oldVersionSettingsFileError, noSettingsFileOnOpenError,
+ tooManySettingsFilesOnOpenError, invalidSettingsError, multipleResetImagesError, resetHotkeyError,
+ pauseHotkeyError, dummySplitsError, alignmentNotMatchedError)
+ from hotkeys import (
+ beforeSettingHotkey, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey,
+ setPauseHotkey)
+
+ myappid = u'Toufool.AutoSplit.v1.5.0'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
# signals
@@ -42,8 +45,8 @@ def __init__(self, parent=None):
self.setupUi(self)
# close all processes when closing window
- self.actionView_Help.triggered.connect(self.viewHelp)
- self.actionAbout.triggered.connect(self.about)
+ self.actionView_Help.triggered.connect(viewHelp)
+ self.actionAbout.triggered.connect(lambda : about(self))
self.actionSave_Settings.triggered.connect(self.saveSettings)
self.actionSave_Settings_As.triggered.connect(self.saveSettingsAs)
self.actionLoad_Settings.triggered.connect(self.loadSettings)
@@ -90,7 +93,6 @@ def __init__(self, parent=None):
self.resetSignal.connect(self.reset)
self.skipSplitSignal.connect(self.skipSplit)
self.undoSplitSignal.connect(self.undoSplit)
- #self.pauseSignal.connect(self.pause)
# live image checkbox
self.liveimageCheckBox.clicked.connect(self.checkLiveImage)
@@ -372,33 +374,19 @@ def autoSplitter(self):
# Make sure that each of the images follows the guidelines for correct format
# according to all of the settings selected by the user.
for image in self.split_image_filenames:
-
- # Check to make sure the file is actually an image format that can be opened
- # according to the mask flag
- if split_parser.flags_from_filename(image) & 0x02 == 0x02:
- source = cv2.imread(self.split_image_directory + image, cv2.IMREAD_UNCHANGED)
-
- if source is None:
- # Opencv couldn't open this file as an image, this isn't a correct
- # file format that is supported
- self.guiChangesOnReset()
- self.imageTypeError(image)
- return
-
- if source.shape[2] != 4:
- # Error, this file doesn't have an alpha channel even
- # though the flag for masking was added
- self.guiChangesOnReset()
- self.alphaChannelError(image)
- return
-
- else:
- if cv2.imread(self.split_image_directory + image, cv2.IMREAD_COLOR) is None:
+ # Test for image without transparency
+ if cv2.imread(self.split_image_directory + image, cv2.IMREAD_COLOR) is None:
+ # Test for image with transparency
+ if cv2.imread(self.split_image_directory + image, cv2.IMREAD_UNCHANGED) is None:
# Opencv couldn't open this file as an image, this isn't a correct
# file format that is supported
self.guiChangesOnReset()
self.imageTypeError(image)
return
+ else:
+ # TODO: Now that we know the image has transparency, error out if it is completely transparent
+ # Will fix https://github.com/Toufool/Auto-Split/issues/52
+ pass
#error out if there is a {p} flag but no pause hotkey set.
if self.pausehotkeyLineEdit.text() == '' and split_parser.flags_from_filename(image) & 0x08 == 0x08:
@@ -406,20 +394,6 @@ def autoSplitter(self):
self.pauseHotkeyError()
return
- if self.custompausetimesCheckBox.isChecked() and split_parser.pause_from_filename(image) is None:
- # Error, this file doesn't have a pause, but the checkbox was
- # selected for unique pause times
- self.guiChangesOnReset()
- self.customPauseError(image)
- return
-
- if self.customthresholdsCheckBox.isChecked() and split_parser.threshold_from_filename(image) is None:
- # Error, this file doesn't have a threshold, but the checkbox
- # was selected for unique thresholds
- self.guiChangesOnReset()
- self.customThresholdError(image)
- return
-
if self.splitLineEdit.text() == '':
self.guiChangesOnReset()
self.splitHotkeyError()
@@ -436,12 +410,6 @@ def autoSplitter(self):
self.multipleResetImagesError()
return
- # if there is no custom threshold for the reset image, throw an error.
- if self.reset_image is not None and self.reset_image_threshold is None:
- self.guiChangesOnReset()
- self.noResetImageThresholdError()
- return
-
# If there is no reset hotkey set but a reset image is present, throw an error.
if self.resetLineEdit.text() == '' and self.reset_image is not None:
self.guiChangesOnReset()
@@ -520,13 +488,9 @@ def autoSplitter(self):
return
# calculate similarity for reset image
- reset_masked = None
- capture = None
+ capture = self.getCaptureForComparison()
if self.shouldCheckResetImage():
- reset_masked = (self.reset_mask is not None)
- capture = self.getCaptureForComparison(reset_masked)
-
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
send_hotkey(self.resetLineEdit.text())
@@ -541,10 +505,10 @@ def autoSplitter(self):
self.guiChangesOnReset()
return
- # get capture again if needed
- masked = (self.flags & 0x02 == 0x02)
- if capture is None or masked != reset_masked:
- capture = self.getCaptureForComparison(masked)
+ # TODO: Check is this actually still needed?
+ # get capture again if current and reset image have different mask flags
+ if self.imageHasTransparency != (self.reset_mask is not None):
+ capture = self.getCaptureForComparison()
# calculate similarity for split image
self.similarity = self.compareImage(self.split_image, self.mask, capture)
@@ -577,18 +541,19 @@ def autoSplitter(self):
else:
self.undosplitButton.setEnabled(True)
- # if the b flag is set, let similarity go above threshold first, then split on similarity below threshold.
+ # if the b flag is set, let similarity go above threshold first,
+ # then split on similarity below threshold.
# if no b flag, just split when similarity goes above threshold.
- if self.flags & 0x04 == 0x04 and self.split_below_threshold == False:
- if self.waiting_for_split_delay == False and self.similarity >= self.similaritythresholdDoubleSpinBox.value():
- self.split_below_threshold = True
- continue
- elif self.flags & 0x04 == 0x04 and self.split_below_threshold == True:
- if self.waiting_for_split_delay == False and self.similarity < self.similaritythresholdDoubleSpinBox.value():
- self.split_below_threshold = False
- break
- else:
- if self.waiting_for_split_delay == False and self.similarity >= self.similaritythresholdDoubleSpinBox.value():
+ if not self.waiting_for_split_delay:
+ if self.flags & 0x04 == 0x04 and not self.split_below_threshold:
+ if self.similarity >= self.similarity_threshold:
+ self.split_below_threshold = True
+ continue
+ elif self.flags & 0x04 == 0x04 and self.split_below_threshold:
+ if self.similarity < self.similarity_threshold:
+ self.split_below_threshold = False
+ break
+ elif self.similarity >= self.similarity_threshold:
break
# limit the number of time the comparison runs to reduce cpu usage
@@ -600,9 +565,7 @@ def autoSplitter(self):
# We need to make sure that this isn't a dummy split before sending
# the key press.
- if (self.flags & 0x01 == 0x01):
- pass
- else:
+ if not (self.flags & 0x01 == 0x01):
# If it's a delayed split, check if the delay has passed
# Otherwise calculate the split time for the key press
if self.split_delay > 0 and self.waiting_for_split_delay == False:
@@ -616,8 +579,8 @@ def autoSplitter(self):
# check for reset while delayed and display a counter of the remaining split delay time
delay_start_time = time.time()
while time.time() - delay_start_time < (self.split_delay / 1000):
- self.delay_time_left = str(round((self.split_delay / 1000) - (time.time() - delay_start_time), 1))
- self.currentSplitImage.setText('Delayed Split: ' + self.delay_time_left + ' sec remaining')
+ delay_time_left = round((self.split_delay / 1000) - (time.time() - delay_start_time), 1)
+ self.currentSplitImage.setText(f'Delayed Split: {delay_time_left} sec remaining')
# check for reset
if win32gui.GetWindowText(self.hwnd) == '':
self.reset()
@@ -630,9 +593,8 @@ def autoSplitter(self):
return
# calculate similarity for reset image
- if self.shouldCheckResetImage() == True:
- reset_masked = (self.reset_mask is not None)
- capture = self.getCaptureForComparison(reset_masked)
+ if self.shouldCheckResetImage():
+ capture = self.getCaptureForComparison()
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
@@ -694,9 +656,9 @@ def autoSplitter(self):
# I have a pause loop here so that it can check if the user presses skip split, undo split, or reset here.
# Also updates the current split image text, counting down the time until the next split image
pause_start_time = time.time()
- while time.time() - pause_start_time < self.pauseDoubleSpinBox.value():
- self.pause_time_left = str(round((self.pauseDoubleSpinBox.value()) - (time.time() - pause_start_time), 1))
- self.currentSplitImage.setText('None (Paused). ' + self.pause_time_left + ' sec remaining')
+ while time.time() - pause_start_time < self.pause:
+ pause_time_left = round(self.pause - (time.time() - pause_start_time), 1)
+ self.currentSplitImage.setText(f'None (Paused). {pause_time_left} sec remaining')
# check for reset
if win32gui.GetWindowText(self.hwnd) == '':
@@ -714,9 +676,8 @@ def autoSplitter(self):
break
# calculate similarity for reset image
- if self.shouldCheckResetImage() == True:
- reset_masked = (self.reset_mask is not None)
- capture = self.getCaptureForComparison(reset_masked)
+ if self.shouldCheckResetImage():
+ capture = self.getCaptureForComparison()
reset_similarity = self.compareImage(self.reset_image, self.reset_mask, capture)
if reset_similarity >= self.reset_image_threshold:
@@ -741,8 +702,6 @@ def guiChangesOnStart(self):
self.setskipsplithotkeyButton.setEnabled(False)
self.setundosplithotkeyButton.setEnabled(False)
self.setpausehotkeyButton.setEnabled(False)
- self.custompausetimesCheckBox.setEnabled(False)
- self.customthresholdsCheckBox.setEnabled(False)
self.groupDummySplitsCheckBox.setEnabled(False)
QtGui.QApplication.processEvents()
@@ -763,8 +722,6 @@ def guiChangesOnReset(self):
self.setskipsplithotkeyButton.setEnabled(True)
self.setundosplithotkeyButton.setEnabled(True)
self.setpausehotkeyButton.setEnabled(True)
- self.custompausetimesCheckBox.setEnabled(True)
- self.customthresholdsCheckBox.setEnabled(True)
self.groupDummySplitsCheckBox.setEnabled(True)
QtGui.QApplication.processEvents()
@@ -784,32 +741,20 @@ def compareImage(self, image, mask, capture):
elif self.comparisonmethodComboBox.currentIndex() == 2:
return compare.compare_phash_masked(image, capture, mask)
- def getCaptureForComparison(self, masked):
+ def getCaptureForComparison(self):
# grab screenshot of capture region
capture = capture_windows.capture_region(self.hwnd, self.rect)
-
- # if flagged as a mask, capture with nearest neighbor interpolation. else don't so that
- # threshold settings on versions below 1.2.0 aren't messed up
- if (masked):
- capture = cv2.resize(capture, (self.RESIZE_WIDTH, self.RESIZE_HEIGHT), interpolation=cv2.INTER_NEAREST)
- else:
- capture = cv2.resize(capture, (self.RESIZE_WIDTH, self.RESIZE_HEIGHT))
-
+ # Capture with nearest neighbor interpolation
+ capture = cv2.resize(capture, (self.RESIZE_WIDTH, self.RESIZE_HEIGHT), interpolation=cv2.INTER_NEAREST)
# convert to BGR
- capture = cv2.cvtColor(capture, cv2.COLOR_BGRA2BGR)
-
- return capture
+ return cv2.cvtColor(capture, cv2.COLOR_BGRA2BGR)
def shouldCheckResetImage(self):
- if self.reset_image is not None and time.time() - self.run_start_time > self.reset_image_pause_time:
- return True
-
- return False
+ return self.reset_image is not None and time.time() - self.run_start_time > self.reset_image_pause_time
def findResetImage(self):
self.reset_image = None
self.reset_mask = None
- self.reset_image_threshold = None
reset_image_file = None
for i, image in enumerate(self.split_image_filenames):
@@ -824,16 +769,15 @@ def findResetImage(self):
# create reset image and keep in memory
path = self.split_image_directory + reset_image_file
- flags = split_parser.flags_from_filename(reset_image_file)
-
- self.reset_image_threshold = split_parser.threshold_from_filename(reset_image_file)
- self.reset_image_pause_time = split_parser.pause_from_filename(reset_image_file)
- if self.reset_image_pause_time is None:
- self.reset_image_pause_time = 0
+ # Override values if they have been specified on the file
+ self.reset_image_pause_time = split_parser.pause_from_filename(reset_image_file) \
+ or self.pauseDoubleSpinBox.value()
+ self.reset_image_threshold = split_parser.threshold_from_filename(reset_image_file) \
+ or self.similaritythresholdDoubleSpinBox.value()
# if theres a mask flag, create a mask
- if (flags & 0x02 == 0x02):
+ if self.imageHasTransparency:
# create mask based on resized, nearest neighbor interpolated split image
self.reset_image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
self.reset_image = cv2.resize(self.reset_image, (self.RESIZE_WIDTH, self.RESIZE_HEIGHT),
@@ -858,10 +802,11 @@ def updateSplitImage(self):
# get flags
self.flags = split_parser.flags_from_filename(split_image_file)
+ self.imageHasTransparency = self.checkIfImageHasTransparency()
# set current split image in UI
# if flagged as mask, transform transparency into UI's gray BG color
- if (self.flags & 0x02 == 0x02):
+ if (self.imageHasTransparency):
self.split_image_display = cv2.imread(self.split_image_path, cv2.IMREAD_UNCHANGED)
transparent_mask = self.split_image_display[:, :, 3] == 0
self.split_image_display[transparent_mask] = [240, 240, 240, 255]
@@ -880,7 +825,7 @@ def updateSplitImage(self):
self.currentsplitimagefileLabel.setText(split_image_file)
# if theres a mask flag, create a mask
- if (self.flags & 0x02 == 0x02):
+ if (self.imageHasTransparency):
# create mask based on resized, nearest neighbor interpolated split image
self.split_image = cv2.imread(self.split_image_path, cv2.IMREAD_UNCHANGED)
@@ -899,12 +844,11 @@ def updateSplitImage(self):
self.split_image = cv2.resize(split_image, (self.RESIZE_WIDTH, self.RESIZE_HEIGHT))
self.mask = None
- # If the unique parameters are selected, go ahead and set the spinboxes to those values
- if self.custompausetimesCheckBox.isChecked():
- self.pauseDoubleSpinBox.setValue(split_parser.pause_from_filename(split_image_file))
-
- if self.customthresholdsCheckBox.isChecked():
- self.similaritythresholdDoubleSpinBox.setValue(split_parser.threshold_from_filename(split_image_file))
+ # Override values if they have been specified on the file
+ self.pause = split_parser.pause_from_filename(split_image_file) \
+ or self.pauseDoubleSpinBox.value()
+ self.similarity_threshold = split_parser.threshold_from_filename(split_image_file) \
+ or self.similaritythresholdDoubleSpinBox.value()
# Get delay for split, if any
self.split_delay = split_parser.delay_from_filename(split_image_file)
@@ -955,7 +899,6 @@ def closeEvent(self, event):
sys.exit()
-
def main():
app = QtGui.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon('icon.ico'))
diff --git a/src/AutoSplit.spec b/src/AutoSplit.spec
new file mode 100644
index 00000000..b05e3229
--- /dev/null
+++ b/src/AutoSplit.spec
@@ -0,0 +1,34 @@
+# -*- mode: python ; coding: utf-8 -*-
+
+
+block_cipher = None
+
+
+a = Analysis(['src\\AutoSplit.py'],
+ pathex=['E:\\Users\\Avasam\\Documents\\Git\\Auto-Split\\src'],
+ binaries=[],
+ datas=[],
+ hiddenimports=[],
+ hookspath=[],
+ runtime_hooks=[],
+ excludes=[],
+ win_no_prefer_redirects=False,
+ win_private_assemblies=False,
+ cipher=block_cipher,
+ noarchive=False)
+pyz = PYZ(a.pure, a.zipped_data,
+ cipher=block_cipher)
+exe = EXE(pyz,
+ a.scripts,
+ a.binaries,
+ a.zipfiles,
+ a.datas,
+ [],
+ name='AutoSplit',
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=True,
+ upx_exclude=[],
+ runtime_tmpdir=None,
+ console=False , icon='src\\icon.ico')
diff --git a/src/capture_windows.py b/src/capture_windows.py
index 7e3d928e..843e2522 100644
--- a/src/capture_windows.py
+++ b/src/capture_windows.py
@@ -1,3 +1,4 @@
+
from ctypes import windll
from ctypes.wintypes import LONG, RECT
from win32 import win32gui
diff --git a/src/compare.py b/src/compare.py
index 72b62913..f2a02f52 100644
--- a/src/compare.py
+++ b/src/compare.py
@@ -1,7 +1,6 @@
from PIL import Image
import imagehash
-
-import numpy
+import numpy as np
import cv2
def compare_histograms(source, capture):
@@ -16,10 +15,10 @@ def compare_histograms(source, capture):
source_hist = cv2.calcHist([source], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
capture_hist = cv2.calcHist([capture], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
-
+
cv2.normalize(source_hist, source_hist)
cv2.normalize(capture_hist, capture_hist)
-
+
return 1 - cv2.compareHist(source_hist, capture_hist, cv2.HISTCMP_BHATTACHARYYA)
def compare_histograms_masked(source, capture, mask):
@@ -34,10 +33,10 @@ def compare_histograms_masked(source, capture, mask):
"""
source_hist = cv2.calcHist([source], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256])
capture_hist = cv2.calcHist([capture], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256])
-
+
cv2.normalize(source_hist, source_hist)
cv2.normalize(capture_hist, capture_hist)
-
+
return 1 - cv2.compareHist(source_hist, capture_hist, cv2.HISTCMP_BHATTACHARYYA)
def compare_l2_norm(source, capture):
@@ -51,10 +50,10 @@ def compare_l2_norm(source, capture):
"""
error = cv2.norm(source, capture, cv2.NORM_L2)
-
+
# The L2 Error is summed across all pixels, so this normalizes
max_error = (source.size ** 0.5) * 255
-
+
return 1 - (error/max_error)
def compare_l2_norm_masked(source, capture, mask):
@@ -71,7 +70,7 @@ def compare_l2_norm_masked(source, capture, mask):
error = cv2.norm(source, capture, cv2.NORM_L2, mask)
# The L2 Error is summed across all pixels, so this normalizes
- max_error = (3 * numpy.count_nonzero(mask) * 255 * 255) ** 0.5
+ max_error = (3 * np.count_nonzero(mask) * 255 * 255) ** 0.5
return 1 - (error / max_error)
@@ -111,13 +110,13 @@ def compare_template_masked(source, capture, mask):
result = cv2.matchTemplate(capture, source, cv2.TM_SQDIFF, None, mask)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
- return 1 - (min_val/numpy.count_nonzero(mask))
+ return 1 - (min_val/np.count_nonzero(mask))
def compare_phash(source, capture):
"""
Compares the pHash of the two given images and returns the similarity between
the two.
-
+
@param source: Image of any given shape as a numpy array
@param capture: Image of any given shape as a numpy array
@return: The similarity between the hashes of the image as a number 0 to 1.
@@ -135,7 +134,7 @@ def compare_phash_masked(source, capture, mask):
"""
Compares the pHash of the two given images and returns the similarity between
the two.
-
+
@param source: Image of any given shape as a numpy array
@param capture: Image of any given shape as a numpy array
@param mask: An image matching the dimensions of the source, but 1 channel grayscale
@@ -149,7 +148,7 @@ def compare_phash_masked(source, capture, mask):
# the same
source = cv2.bitwise_and(source, source, mask=mask)
capture = cv2.bitwise_and(capture, capture, mask=mask)
-
+
source = Image.fromarray(source)
capture = Image.fromarray(capture)
@@ -157,3 +156,9 @@ def compare_phash_masked(source, capture, mask):
capture_hash = imagehash.phash(capture)
return 1 - ((source_hash - capture_hash)/64.0)
+
+
+def checkIfImageHasTransparency(self):
+ source = cv2.imread(self.split_image_path, cv2.IMREAD_UNCHANGED)
+ # Check if there's a transparency channel (4th channel) and if at least one pixel is transparent (< 255)
+ return source.shape[2] == 4 and np.mean(source[:, :, 3]) != 255
diff --git a/src/design.py b/src/design.py
index 1d74fd47..eba9c843 100644
--- a/src/design.py
+++ b/src/design.py
@@ -77,7 +77,7 @@ def setupUi(self, MainWindow):
self.selectregionButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.selectregionButton.setObjectName(_fromUtf8("selectregionButton"))
self.similaritythresholdLabel = QtGui.QLabel(self.centralwidget)
- self.similaritythresholdLabel.setGeometry(QtCore.QRect(10, 378, 91, 16))
+ self.similaritythresholdLabel.setGeometry(QtCore.QRect(10, 374, 91, 22))
self.similaritythresholdLabel.setObjectName(_fromUtf8("similaritythresholdLabel"))
self.similaritythresholdDoubleSpinBox = QtGui.QDoubleSpinBox(self.centralwidget)
self.similaritythresholdDoubleSpinBox.setGeometry(QtCore.QRect(160, 383, 64, 22))
@@ -102,7 +102,7 @@ def setupUi(self, MainWindow):
self.skipsplitButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.skipsplitButton.setObjectName(_fromUtf8("skipsplitButton"))
self.pauseLabel = QtGui.QLabel(self.centralwidget)
- self.pauseLabel.setGeometry(QtCore.QRect(10, 420, 140, 16))
+ self.pauseLabel.setGeometry(QtCore.QRect(10, 420, 111, 22))
self.pauseLabel.setObjectName(_fromUtf8("pauseLabel"))
self.checkfpsButton = QtGui.QPushButton(self.centralwidget)
self.checkfpsButton.setGeometry(QtCore.QRect(5, 225, 51, 21))
@@ -343,20 +343,6 @@ def setupUi(self, MainWindow):
self.pauseDoubleSpinBox.setSingleStep(1.0)
self.pauseDoubleSpinBox.setProperty("value", 10.0)
self.pauseDoubleSpinBox.setObjectName(_fromUtf8("pauseDoubleSpinBox"))
- self.custompausetimesCheckBox = QtGui.QCheckBox(self.centralwidget)
- self.custompausetimesCheckBox.setEnabled(True)
- self.custompausetimesCheckBox.setGeometry(QtCore.QRect(10, 435, 121, 17))
- self.custompausetimesCheckBox.setWhatsThis(_fromUtf8(""))
- self.custompausetimesCheckBox.setChecked(False)
- self.custompausetimesCheckBox.setTristate(False)
- self.custompausetimesCheckBox.setObjectName(_fromUtf8("custompausetimesCheckBox"))
- self.customthresholdsCheckBox = QtGui.QCheckBox(self.centralwidget)
- self.customthresholdsCheckBox.setEnabled(True)
- self.customthresholdsCheckBox.setGeometry(QtCore.QRect(10, 394, 111, 17))
- self.customthresholdsCheckBox.setWhatsThis(_fromUtf8(""))
- self.customthresholdsCheckBox.setChecked(False)
- self.customthresholdsCheckBox.setTristate(False)
- self.customthresholdsCheckBox.setObjectName(_fromUtf8("customthresholdsCheckBox"))
self.comparisonmethodLabel = QtGui.QLabel(self.centralwidget)
self.comparisonmethodLabel.setGeometry(QtCore.QRect(10, 300, 101, 16))
self.comparisonmethodLabel.setObjectName(_fromUtf8("comparisonmethodLabel"))
@@ -438,8 +424,6 @@ def setupUi(self, MainWindow):
self.yLabel.raise_()
self.comparisonmethodComboBox.raise_()
self.pauseDoubleSpinBox.raise_()
- self.custompausetimesCheckBox.raise_()
- self.customthresholdsCheckBox.raise_()
self.comparisonmethodLabel.raise_()
self.alignregionButton.raise_()
self.groupDummySplitsCheckBox.raise_()
@@ -482,10 +466,8 @@ def setupUi(self, MainWindow):
MainWindow.setTabOrder(self.liveimageCheckBox, self.comparisonmethodComboBox)
MainWindow.setTabOrder(self.comparisonmethodComboBox, self.showlivesimilarityCheckBox)
MainWindow.setTabOrder(self.showlivesimilarityCheckBox, self.showhighestsimilarityCheckBox)
- MainWindow.setTabOrder(self.showhighestsimilarityCheckBox, self.customthresholdsCheckBox)
- MainWindow.setTabOrder(self.customthresholdsCheckBox, self.similaritythresholdDoubleSpinBox)
- MainWindow.setTabOrder(self.similaritythresholdDoubleSpinBox, self.custompausetimesCheckBox)
- MainWindow.setTabOrder(self.custompausetimesCheckBox, self.pauseDoubleSpinBox)
+ MainWindow.setTabOrder(self.showhighestsimilarityCheckBox, self.similaritythresholdDoubleSpinBox)
+ MainWindow.setTabOrder(self.similaritythresholdDoubleSpinBox, self.pauseDoubleSpinBox)
MainWindow.setTabOrder(self.pauseDoubleSpinBox, self.splitLineEdit)
MainWindow.setTabOrder(self.splitLineEdit, self.resetLineEdit)
MainWindow.setTabOrder(self.resetLineEdit, self.skipsplitLineEdit)
@@ -504,12 +486,12 @@ def retranslateUi(self, MainWindow):
self.loopCheckBox.setText(_translate("MainWindow", "Loop Split Images", None))
self.autostartonresetCheckBox.setText(_translate("MainWindow", "Auto Start On Reset", None))
self.selectregionButton.setText(_translate("MainWindow", "Select Region", None))
- self.similaritythresholdLabel.setText(_translate("MainWindow", "Similarity threshold", None))
+ self.similaritythresholdLabel.setText(_translate("MainWindow", "Similarity threshold\nDefault value", None))
self.startautosplitterButton.setText(_translate("MainWindow", "Start Auto Splitter", None))
self.resetButton.setText(_translate("MainWindow", "Reset", None))
self.undosplitButton.setText(_translate("MainWindow", "Undo Split", None))
self.skipsplitButton.setText(_translate("MainWindow", "Skip Split", None))
- self.pauseLabel.setText(_translate("MainWindow", "Pause time after split (sec)", None))
+ self.pauseLabel.setText(_translate("MainWindow", "Pause time (seconds)\nDefault value", None))
self.checkfpsButton.setText(_translate("MainWindow", "Max FPS", None))
self.fpsLabel.setText(_translate("MainWindow", "FPS", None))
self.showlivesimilarityCheckBox.setText(_translate("MainWindow", "Show live similarity", None))
@@ -536,8 +518,6 @@ def retranslateUi(self, MainWindow):
self.comparisonmethodComboBox.setItemText(0, _translate("MainWindow", "L2 Norm", None))
self.comparisonmethodComboBox.setItemText(1, _translate("MainWindow", "Histograms", None))
self.comparisonmethodComboBox.setItemText(2, _translate("MainWindow", "pHash", None))
- self.custompausetimesCheckBox.setText(_translate("MainWindow", "Custom pause times", None))
- self.customthresholdsCheckBox.setText(_translate("MainWindow", "Custom thresholds", None))
self.comparisonmethodLabel.setText(_translate("MainWindow", "Comparison Method", None))
self.alignregionButton.setText(_translate("MainWindow", "Align Region", None))
self.groupDummySplitsCheckBox.setText(_translate("MainWindow", "Group dummy splits when undoing/skipping", None))
diff --git a/src/error_messages.py b/src/error_messages.py
index 2f55c83f..f2a7fdd2 100644
--- a/src/error_messages.py
+++ b/src/error_messages.py
@@ -1,6 +1,7 @@
# Error messages
from PyQt4 import QtGui
+
def splitImageDirectoryError(self):
msgBox = QtGui.QMessageBox()
msgBox.setWindowTitle('Error')
@@ -48,27 +49,6 @@ def pauseHotkeyError(self):
msgBox.setText("Your split image folder contains an image filename with a pause flag {p}, but no pause hotkey is set.")
msgBox.exec_()
-def customThresholdError(self, image):
- msgBox = QtGui.QMessageBox()
- msgBox.setWindowTitle('Error')
- msgBox.setText("\"" + image + "\" doesn't have a valid custom threshold.")
- msgBox.exec_()
-
-
-def customPauseError(self, image):
- msgBox = QtGui.QMessageBox()
- msgBox.setWindowTitle('Error')
- msgBox.setText("\"" + image + "\" doesn't have a valid custom pause time.")
- msgBox.exec_()
-
-
-def alphaChannelError(self, image):
- msgBox = QtGui.QMessageBox()
- msgBox.setWindowTitle('Error')
- msgBox.setText("\"" + image + "\" is marked with mask flag but it doesn't have transparency.")
- msgBox.exec_()
-
-
def alignRegionImageTypeError(self):
msgBox = QtGui.QMessageBox()
msgBox.setWindowTitle('Error')
@@ -90,13 +70,6 @@ def multipleResetImagesError(self):
msgBox.exec_()
-def noResetImageThresholdError(self):
- msgBox = QtGui.QMessageBox()
- msgBox.setWindowTitle('Error')
- msgBox.setText("Reset Image must have a custom threshold. Please set one and check that it is valid")
- msgBox.exec_()
-
-
def resetHotkeyError(self):
msgBox = QtGui.QMessageBox()
msgBox.setWindowTitle('Error')
@@ -111,12 +84,6 @@ def dummySplitsError(self):
"Group dummy splits when undoing/skipping cannot be checked if any split image has a loop parameter greater than 1")
msgBox.exec_()
-def settingsNotFoundError(self):
- msgBox = QtGui.QMessageBox()
- msgBox.setWindowTitle('Error')
- msgBox.setText("No settings file found. The settings file is saved when the program is closed.")
- msgBox.exec_()
-
def oldVersionSettingsFileError(self):
msgBox = QtGui.QMessageBox()
msgBox.setWindowTitle('Error')
@@ -139,4 +106,4 @@ def tooManySettingsFilesOnOpenError(self):
msgBox = QtGui.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Too many settings files found. Only one can be loaded on open if placed in the same folder as AutoSplit.exe")
- msgBox.exec_()
\ No newline at end of file
+ msgBox.exec_()
diff --git a/src/screen_region.py b/src/screen_region.py
index 9c9d382a..6de9b2b6 100644
--- a/src/screen_region.py
+++ b/src/screen_region.py
@@ -1,13 +1,8 @@
from PyQt4 import QtGui, QtCore, QtTest
-import ctypes
-import ctypes.wintypes
-import win32gui
-import cv2
+from win32 import win32gui
import capture_windows
-from PyQt4 import QtGui, QtCore, QtTest
import ctypes
import ctypes.wintypes
-import win32gui
import cv2
import numpy as np
@@ -291,4 +286,4 @@ def mouseReleaseEvent(self, event):
self.bottom = max(self.begin.y(), self.end.y()) + self.SM_YVIRTUALSCREEN
self.height = self.bottom - self.top
- self.width = self.right - self.left
\ No newline at end of file
+ self.width = self.right - self.left
diff --git a/src/settings_file.py b/src/settings_file.py
index 9f352cb7..ef8d3006 100644
--- a/src/settings_file.py
+++ b/src/settings_file.py
@@ -1,11 +1,8 @@
+from win32 import win32gui
+from PyQt4 import QtGui
import keyboard
-import win32gui
import pickle
import glob
-import logging
-from PyQt4 import QtGui
-from hotkeys import _hotkey_action
-
def getSaveSettingsValues(self):
# get values to be able to save settings
@@ -24,15 +21,8 @@ def getSaveSettingsValues(self):
self.undo_split_key = str(self.undosplitLineEdit.text())
self.pause_key = str(self.pausehotkeyLineEdit.text())
- if self.custompausetimesCheckBox.isChecked():
- self.custom_pause_times_setting = 1
- else:
- self.custom_pause_times_setting = 0
-
- if self.customthresholdsCheckBox.isChecked():
- self.custom_thresholds_setting = 1
- else:
- self.custom_thresholds_setting = 0
+ self.custom_pause_times_setting = 0
+ self.custom_thresholds_setting = 1
if self.groupDummySplitsCheckBox.isChecked():
self.group_dummy_splits_undo_skip_setting = 1
@@ -51,12 +41,27 @@ def getSaveSettingsValues(self):
def haveSettingsChanged(self):
self.getSaveSettingsValues()
- self.current_save_settings = [self.split_image_directory, self.similarity_threshold, self.comparison_index, self.pause,
- self.fps_limit, self.split_key,
- self.reset_key, self.skip_split_key, self.undo_split_key, self.pause_key, self.x, self.y, self.width, self.height,
- self.hwnd_title,
- self.custom_pause_times_setting, self.custom_thresholds_setting,
- self.group_dummy_splits_undo_skip_setting, self.loop_setting, self.auto_start_on_reset_setting]
+ self.current_save_settings = [
+ self.split_image_directory,
+ self.similarity_threshold,
+ self.comparison_index,
+ self.pause,
+ self.fps_limit,
+ self.split_key,
+ self.reset_key,
+ self.skip_split_key,
+ self.undo_split_key,
+ self.pause_key,
+ self.x,
+ self.y,
+ self.width,
+ self.height,
+ self.hwnd_title,
+ self.custom_pause_times_setting,
+ self.custom_thresholds_setting,
+ self.group_dummy_splits_undo_skip_setting,
+ self.loop_setting,
+ self.auto_start_on_reset_setting]
#one small caveat in this: if you load a settings file from an old version, but dont change settings,
#the current save settings and last load settings will have different # of elements and it will ask
@@ -71,14 +76,27 @@ def saveSettings(self):
self.saveSettingsAs()
else:
self.getSaveSettingsValues()
- self.last_saved_settings = [self.split_image_directory, self.similarity_threshold, self.comparison_index,
- self.pause,
- self.fps_limit, self.split_key,
- self.reset_key, self.skip_split_key, self.undo_split_key, self.pause_key, self.x,
- self.y, self.width, self.height,
- self.hwnd_title,
- self.custom_pause_times_setting, self.custom_thresholds_setting,
- self.group_dummy_splits_undo_skip_setting, self.loop_setting, self.auto_start_on_reset_setting]
+ self.last_saved_settings = [
+ self.split_image_directory,
+ self.similarity_threshold,
+ self.comparison_index,
+ self.pause,
+ self.fps_limit,
+ self.split_key,
+ self.reset_key,
+ self.skip_split_key,
+ self.undo_split_key,
+ self.pause_key,
+ self.x,
+ self.y,
+ self.width,
+ self.height,
+ self.hwnd_title,
+ self.custom_pause_times_setting,
+ self.custom_thresholds_setting,
+ self.group_dummy_splits_undo_skip_setting,
+ self.loop_setting,
+ self.auto_start_on_reset_setting]
# save settings to a .pkl file
with open(self.last_successfully_loaded_settings_file_path, 'wb') as f:
pickle.dump(self.last_saved_settings, f)
@@ -92,12 +110,27 @@ def saveSettingsAs(self):
return
self.getSaveSettingsValues()
- self.last_saved_settings = [self.split_image_directory, self.similarity_threshold, self.comparison_index, self.pause,
- self.fps_limit, self.split_key,
- self.reset_key, self.skip_split_key, self.undo_split_key, self.pause_key, self.x, self.y, self.width, self.height,
- self.hwnd_title,
- self.custom_pause_times_setting, self.custom_thresholds_setting,
- self.group_dummy_splits_undo_skip_setting, self.loop_setting, self.auto_start_on_reset_setting]
+ self.last_saved_settings = [
+ self.split_image_directory,
+ self.similarity_threshold,
+ self.comparison_index,
+ self.pause,
+ self.fps_limit,
+ self.split_key,
+ self.reset_key,
+ self.skip_split_key,
+ self.undo_split_key,
+ self.pause_key,
+ self.x,
+ self.y,
+ self.width,
+ self.height,
+ self.hwnd_title,
+ self.custom_pause_times_setting,
+ self.custom_thresholds_setting,
+ self.group_dummy_splits_undo_skip_setting,
+ self.loop_setting,
+ self.auto_start_on_reset_setting]
# save settings to a .pkl file
with open(self.save_settings_file_path, 'wb') as f:
@@ -142,21 +175,49 @@ def loadSettings(self):
#v1.5 settings
if self.settings_count == 20:
with open(self.load_settings_file_path, 'rb') as f:
- self.last_loaded_settings = [self.split_image_directory, self.similarity_threshold, self.comparison_index, self.pause,
- self.fps_limit, self.split_key,
- self.reset_key, self.skip_split_key, self.undo_split_key, self.pause_key, self.x, self.y, self.width, self.height,
- self.hwnd_title,
- self.custom_pause_times_setting, self.custom_thresholds_setting,
- self.group_dummy_splits_undo_skip_setting, self.loop_setting, self.auto_start_on_reset_setting] = pickle.load(f)
+ self.last_loaded_settings = [
+ self.split_image_directory,
+ self.similarity_threshold,
+ self.comparison_index,
+ self.pause,
+ self.fps_limit,
+ self.split_key,
+ self.reset_key,
+ self.skip_split_key,
+ self.undo_split_key,
+ self.pause_key,
+ self.x,
+ self.y,
+ self.width,
+ self.height,
+ self.hwnd_title,
+ self.custom_pause_times_setting,
+ self.custom_thresholds_setting,
+ self.group_dummy_splits_undo_skip_setting,
+ self.loop_setting,
+ self.auto_start_on_reset_setting] = pickle.load(f)
#v1.3-1.4 settings. add a blank pause key.
elif self.settings_count == 18:
with open(self.load_settings_file_path, 'rb') as f:
- self.last_loaded_settings = [self.split_image_directory, self.similarity_threshold, self.comparison_index, self.pause,
- self.fps_limit, self.split_key,
- self.reset_key, self.skip_split_key, self.undo_split_key, self.x, self.y, self.width, self.height,
- self.hwnd_title,
- self.custom_pause_times_setting, self.custom_thresholds_setting,
- self.group_dummy_splits_undo_skip_setting, self.loop_setting] = pickle.load(f)
+ self.last_loaded_settings = [
+ self.split_image_directory,
+ self.similarity_threshold,
+ self.comparison_index,
+ self.pause,
+ self.fps_limit,
+ self.split_key,
+ self.reset_key,
+ self.skip_split_key,
+ self.undo_split_key,
+ self.x,
+ self.y,
+ self.width,
+ self.height,
+ self.hwnd_title,
+ self.custom_pause_times_setting,
+ self.custom_thresholds_setting,
+ self.group_dummy_splits_undo_skip_setting,
+ self.loop_setting] = pickle.load(f)
self.pause_key = ''
self.auto_start_on_reset_setting = 0
elif self.settings_count < 18:
@@ -174,13 +235,22 @@ def loadSettings(self):
self.heightSpinBox.setValue(self.height)
self.comparisonmethodComboBox.setCurrentIndex(self.comparison_index)
self.hwnd = win32gui.FindWindow(None, self.hwnd_title)
+
+ # set custom checkboxes accordingly
+ if self.group_dummy_splits_undo_skip_setting == 1:
+ self.groupDummySplitsCheckBox.setChecked(True)
+ else:
+ self.groupDummySplitsCheckBox.setChecked(False)
- # set custom checkbox's accordingly
- self.custompausetimesCheckBox.setChecked(self.custom_pause_times_setting == 1)
- self.customthresholdsCheckBox.setChecked(self.custom_thresholds_setting == 1)
- self.groupDummySplitsCheckBox.setChecked(self.group_dummy_splits_undo_skip_setting == 1)
- self.loopCheckBox.setChecked(self.loop_setting == 1)
- self.autostartonresetCheckBox.setChecked(self.auto_start_on_reset_setting == 1)
+ if self.loop_setting == 1:
+ self.loopCheckBox.setChecked(True)
+ else:
+ self.loopCheckBox.setChecked(False)
+
+ if self.auto_start_on_reset_setting == 1:
+ self.autostartonresetCheckBox.setChecked(True)
+ else:
+ self.autostartonresetCheckBox.setChecked(False)
# TODO: Reuse code from hotkeys rather than duplicating here
# try to set hotkeys from when user last closed the window
diff --git a/src/split_parser.py b/src/split_parser.py
index 2b6d9bc1..74d9fe42 100644
--- a/src/split_parser.py
+++ b/src/split_parser.py
@@ -6,7 +6,7 @@ def threshold_from_filename(filename):
@param filename: String containing the file's name
@return: A valid threshold, if not then None
"""
-
+
# Check to make sure there is a valid floating point number between
# parentheses of the filename
try:
@@ -97,7 +97,6 @@ def flags_from_filename(filename):
"""
List of flags:
'd' = dummy, do nothing when this split is found
- 'm' = mask, use a mask when comparing this split
'b' = below threshold, after threshold is met, split when it goes below the threhsold.
'p' = pause, hit pause key when this split is found
"""
@@ -110,17 +109,14 @@ def flags_from_filename(filename):
return 0
DUMMY_FLAG = 1 << 0
- MASK_FLAG = 1 << 1
BELOW_FLAG = 1 << 2
PAUSE_FLAG = 1 << 3
flags = 0x00
-
+
for c in flags_str:
if c.upper() == 'D':
flags |= DUMMY_FLAG
- elif c.upper() == 'M':
- flags |= MASK_FLAG
elif c.upper() == 'B':
flags |= BELOW_FLAG
elif c.upper() == 'P':
@@ -134,7 +130,7 @@ def flags_from_filename(filename):
# For instance, we can't have a dummy split also pause
if (flags & DUMMY_FLAG == DUMMY_FLAG) and (flags & PAUSE_FLAG == PAUSE_FLAG):
return 0
-
+
return flags
def is_reset_image(filename):
@@ -144,4 +140,4 @@ def is_reset_image(filename):
@param filename: String containing the file's name
@return: True if its a reset image
"""
- return ('RESET' in filename.upper())
\ No newline at end of file
+ return ('RESET' in filename.upper())
From 187a7d932da05ea96612c6320cfcb0f742f0658f Mon Sep 17 00:00:00 2001
From: Avasam
Date: Tue, 9 Nov 2021 21:55:55 -0500
Subject: [PATCH 5/8] Added install and build scripts
---
.vscode/settings.json | 8 --------
README.md | 12 ++++--------
scripts/build.bat | 1 +
scripts/compile_resources.bat | 6 ++++++
scripts/install.bat | 1 +
requirements.txt => scripts/requirements.txt | 7 ++-----
6 files changed, 14 insertions(+), 21 deletions(-)
create mode 100644 scripts/build.bat
create mode 100644 scripts/compile_resources.bat
create mode 100644 scripts/install.bat
rename requirements.txt => scripts/requirements.txt (59%)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 977842be..3e2705c9 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -18,14 +18,6 @@
120,
]
},
- "[py]": {
- "editor.tabSize": 4,
- "editor.rulers": [
- 72,
- 79,
- 120,
- ]
- },
// Keeping autoformat to false for now to keep minimal changes
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
diff --git a/README.md b/README.md
index 473df18d..97dcf4d6 100644
--- a/README.md
+++ b/README.md
@@ -2,19 +2,17 @@
This program compares split images to a capture region of any window (OBS, xsplit, etc.) and automatically hits your split hotkey when there is a match. It can be used in tandem with any speedrun timer that accepts hotkeys (LiveSplit, wsplit, etc.). The purpose of this program is to remove the need to manually press your split hotkey and also increase the accuracy of your splits.
-
-
-
+
# TUTORIAL
## DOWNLOAD AND OPEN
### Compatability
-- Windows 7, 10, and 11
+- Windows 7, 10, and 11.
### Building
-- Read [requirements.txt](/requirements.txt) for information on how to run/build the python code
+- Read [requirements.txt](/scripts/requirements.txt) for information on how to run/build the python code
### Opening the program
- Download the [latest version](https://github.com/austinryan/Auto-Split/releases)
@@ -90,9 +88,7 @@ This program compares split images to a capture region of any window (OBS, xspli
### How to Create a Masked Image
The best way to create a masked image is to set your capture region as the entire game screen, take a screenshot, and use a program like [paint.net](https://www.getpaint.net/) to "erase" (make transparent) everything you don't want the program to compare. More on how to creating images with transparency using paint.net can be found in [this tutorial](https://www.youtube.com/watch?v=v53kkUYFVn8). The last thing you need to do is add {m} to the filename. For visualization, here is what the capture region compared to a masked split image looks like if you would want to split on "Shine Get!" text in Super Mario Sunshine:
-
-
-
+
### Reset image
You can have one (and only one) image with the keyword `reset` in its name. AutoSplit will press the reset button when it finds this image. This image will only be used for resets and it will not be tied to any split. You can set a probability and pause time for it. A custom threshold MUST be applied to this image. The pause time is the amount of seconds AutoSplit will wait before checking for the reset image once the run starts. Also the image can be masked, for example: `Reset_(0.95)_[10]_{m}.png`.
diff --git a/scripts/build.bat b/scripts/build.bat
new file mode 100644
index 00000000..4c727460
--- /dev/null
+++ b/scripts/build.bat
@@ -0,0 +1 @@
+pyinstaller -w -F --icon=src/icon.ico "%~p0/../src/AutoSplit.py"
diff --git a/scripts/compile_resources.bat b/scripts/compile_resources.bat
new file mode 100644
index 00000000..5c6670bc
--- /dev/null
+++ b/scripts/compile_resources.bat
@@ -0,0 +1,6 @@
+cd "%~dp0.."
+pyuic6 "./res/about.ui" -o "./src/about.py"
+pyuic6 "./res/design.ui" -o "./src/design.py"
+:: Doesn't work with current setup. Files might have to be moved around.
+:: The Donate button file is also missing
+pyside6-rcc "./res/resources.qrc" -o "./src/resources_rc.py"
diff --git a/scripts/install.bat b/scripts/install.bat
new file mode 100644
index 00000000..3e7a76b0
--- /dev/null
+++ b/scripts/install.bat
@@ -0,0 +1 @@
+pip3 install -r "%~p0/requirements.txt"
diff --git a/requirements.txt b/scripts/requirements.txt
similarity index 59%
rename from requirements.txt
rename to scripts/requirements.txt
index a6af9ffc..416568eb 100644
--- a/requirements.txt
+++ b/scripts/requirements.txt
@@ -1,6 +1,6 @@
# Requirements file for AutoSplit
#
-# Python: CPython 3.7 (not 3.8 as there is no cp38 wheel for PyQt4)
+# Python: CPython 3.7+
#
# Usage: pip3.7 install -r requirements.txt
#
@@ -9,14 +9,11 @@
#
# Creating AutoSplit.exe with PyInstaller: pyinstaller -w -F --hidden-import sip --icon=src\icon.ico src\AutoSplit.py
#
-# You can find other wheels here: https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyqt4
-https://download.lfd.uci.edu/pythonlibs/q4trcu4l/PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
-# https://download.lfd.uci.edu/pythonlibs/q4trcu4l/PyQt4-4.11.4-cp37-cp37m-win32.whl
-#
# Comment this out if you don't want to create AutoSplit.exe:
PyInstaller
#
# Other dependencies:
+PyQT5==5.9
opencv-python
Pillow
ImageHash
From 505ddb0a21129c3491465b319da904618b6c1f5c Mon Sep 17 00:00:00 2001
From: Avasam
Date: Tue, 9 Nov 2021 21:55:59 -0500
Subject: [PATCH 6/8] Migrated from PyQt4 to PyQt5
---
src/AutoSplit.py | 26 ++---
src/about.py | 28 +++---
src/capture_windows.py | 1 -
src/design.py | 222 ++++++++++++++++++++---------------------
src/error_messages.py | 34 +++----
src/menu_bar.py | 4 +-
src/resources_rc.py | 4 +-
src/screen_region.py | 12 +--
src/settings_file.py | 7 +-
9 files changed, 169 insertions(+), 169 deletions(-)
diff --git a/src/AutoSplit.py b/src/AutoSplit.py
index bd627b71..0050adf1 100644
--- a/src/AutoSplit.py
+++ b/src/AutoSplit.py
@@ -1,7 +1,7 @@
#!/usr/bin/python3.7
# -*- coding: utf-8 -*-
-from PyQt4 import QtGui, QtCore, QtTest
+from PyQt5 import QtCore, QtGui, QtTest, QtWidgets
from menu_bar import about, viewHelp
from win32 import win32gui
import sys
@@ -11,6 +11,7 @@
import ctypes.wintypes
import ctypes
import numpy as np
+
from hotkeys import send_hotkey
import design
import compare
@@ -27,8 +28,7 @@ class AutoSplit(QtWidgets.QMainWindow, design.Ui_MainWindow):
from hotkeys import (
beforeSettingHotkey, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, setUndoSplitHotkey,
setPauseHotkey)
-
- myappid = u'Toufool.AutoSplit.v1.5.0'
+ myappid = u'Toufool.AutoSplit.v1.5.1'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
# signals
@@ -46,7 +46,7 @@ def __init__(self, parent=None):
# close all processes when closing window
self.actionView_Help.triggered.connect(viewHelp)
- self.actionAbout.triggered.connect(lambda : about(self))
+ self.actionAbout.triggered.connect(lambda: about(self))
self.actionSave_Settings.triggered.connect(self.saveSettings)
self.actionSave_Settings_As.triggered.connect(self.saveSettingsAs)
self.actionLoad_Settings.triggered.connect(self.loadSettings)
@@ -123,7 +123,7 @@ def __init__(self, parent=None):
def browse(self):
# User selects the file with the split images in it.
self.split_image_directory = str(
- QtGui.QFileDialog.getExistingDirectory(self, "Select Split Image Directory")) + '\\'
+ QtWidgets.QFileDialog.getExistingDirectory(self, "Select Split Image Directory")) + '\\'
# If the user doesn't select a folder, it defaults to \. Set it back to whats in the LineEdit, and return
if self.split_image_directory == '\\':
@@ -465,7 +465,7 @@ def autoSplitter(self):
if self.waiting_for_split_delay == True:
time_millis = int(round(time.time() * 1000))
if time_millis < self.split_time:
- QtGui.QApplication.processEvents()
+ QtWidgets.QApplication.processEvents()
continue
self.updateSplitImage()
@@ -559,7 +559,7 @@ def autoSplitter(self):
# limit the number of time the comparison runs to reduce cpu usage
fps_limit = self.fpslimitSpinBox.value()
time.sleep((1 / fps_limit) - (time.time() - start) % (1 / fps_limit))
- QtGui.QApplication.processEvents()
+ QtWidgets.QApplication.processEvents()
# comes here when threshold gets met
@@ -651,7 +651,7 @@ def autoSplitter(self):
else:
self.undosplitButton.setEnabled(True)
- QtGui.QApplication.processEvents()
+ QtWidgets.QApplication.processEvents()
# I have a pause loop here so that it can check if the user presses skip split, undo split, or reset here.
# Also updates the current split image text, counting down the time until the next split image
@@ -703,7 +703,7 @@ def guiChangesOnStart(self):
self.setundosplithotkeyButton.setEnabled(False)
self.setpausehotkeyButton.setEnabled(False)
self.groupDummySplitsCheckBox.setEnabled(False)
- QtGui.QApplication.processEvents()
+ QtWidgets.QApplication.processEvents()
def guiChangesOnReset(self):
self.startautosplitterButton.setText('Start Auto Splitter')
@@ -723,7 +723,7 @@ def guiChangesOnReset(self):
self.setundosplithotkeyButton.setEnabled(True)
self.setpausehotkeyButton.setEnabled(True)
self.groupDummySplitsCheckBox.setEnabled(True)
- QtGui.QApplication.processEvents()
+ QtWidgets.QApplication.processEvents()
def compareImage(self, image, mask, capture):
if mask is None:
@@ -867,7 +867,7 @@ def closeEvent(self, event):
if self.haveSettingsChanged():
#give a different warning if there was never a settings file that was loaded successfully, and save as instead of save.
if self.last_successfully_loaded_settings_file_path == None:
- msgBox = QtGui.QMessageBox
+ msgBox = QtWidgets.QMessageBox
warning = msgBox.warning(self, "AutoSplit","Do you want to save changes made to settings file Untitled?", msgBox.Yes | msgBox.No | msgBox.Cancel)
if warning == msgBox.Yes:
self.saveSettingsAs()
@@ -881,7 +881,7 @@ def closeEvent(self, event):
event.ignore()
return
else:
- msgBox = QtGui.QMessageBox
+ msgBox = QtWidgets.QMessageBox
warning = msgBox.warning(self, "AutoSplit", "Do you want to save the changes made to the settings file " + os.path.basename(self.last_successfully_loaded_settings_file_path) + " ?", msgBox.Yes | msgBox.No | msgBox.Cancel)
if warning == msgBox.Yes:
self.saveSettings()
@@ -900,7 +900,7 @@ def closeEvent(self, event):
def main():
- app = QtGui.QApplication(sys.argv)
+ app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon('icon.ico'))
w = AutoSplit()
w.setWindowIcon(QtGui.QIcon('icon.ico'))
diff --git a/src/about.py b/src/about.py
index 93f90bfe..a34864b2 100644
--- a/src/about.py
+++ b/src/about.py
@@ -2,11 +2,11 @@
# Form implementation generated from reading ui file 'about.ui'
#
-# Created by: PyQt4 UI code generator 4.11.4
+# Created by: PyQt5 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
-from PyQt4 import QtCore, QtGui
+from PyQt5 import QtCore, QtGui, QtWidgets
try:
_fromUtf8 = QtCore.QString.fromUtf8
@@ -15,12 +15,12 @@ def _fromUtf8(s):
return s
try:
- _encoding = QtGui.QApplication.UnicodeUTF8
+ _encoding = QtWidgets.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
- return QtGui.QApplication.translate(context, text, disambig, _encoding)
+ return QtWidgets.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
- return QtGui.QApplication.translate(context, text, disambig)
+ return QtWidgets.QApplication.translate(context, text, disambig)
class Ui_aboutAutoSplitWidget(object):
def setupUi(self, aboutAutoSplitWidget):
@@ -31,28 +31,28 @@ def setupUi(self, aboutAutoSplitWidget):
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/resources/icon.ico")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
aboutAutoSplitWidget.setWindowIcon(icon)
- self.okButton = QtGui.QPushButton(aboutAutoSplitWidget)
+ self.okButton = QtWidgets.QPushButton(aboutAutoSplitWidget)
self.okButton.setGeometry(QtCore.QRect(190, 220, 71, 21))
self.okButton.setObjectName(_fromUtf8("okButton"))
- self.createdbyLabel = QtGui.QLabel(aboutAutoSplitWidget)
+ self.createdbyLabel = QtWidgets.QLabel(aboutAutoSplitWidget)
self.createdbyLabel.setGeometry(QtCore.QRect(10, 44, 151, 16))
self.createdbyLabel.setObjectName(_fromUtf8("createdbyLabel"))
- self.versionLabel = QtGui.QLabel(aboutAutoSplitWidget)
+ self.versionLabel = QtWidgets.QLabel(aboutAutoSplitWidget)
self.versionLabel.setGeometry(QtCore.QRect(10, 21, 71, 16))
self.versionLabel.setObjectName(_fromUtf8("versionLabel"))
- self.donatetextLabel = QtGui.QLabel(aboutAutoSplitWidget)
+ self.donatetextLabel = QtWidgets.QLabel(aboutAutoSplitWidget)
self.donatetextLabel.setGeometry(QtCore.QRect(46, 95, 191, 41))
self.donatetextLabel.setObjectName(_fromUtf8("donatetextLabel"))
- self.donatebuttonLabel = QtGui.QLabel(aboutAutoSplitWidget)
+ self.donatebuttonLabel = QtWidgets.QLabel(aboutAutoSplitWidget)
self.donatebuttonLabel.setGeometry(QtCore.QRect(52, 127, 171, 91))
self.donatebuttonLabel.setAlignment(QtCore.Qt.AlignCenter)
self.donatebuttonLabel.setObjectName(_fromUtf8("donatebuttonLabel"))
- self.iconLabel = QtGui.QLabel(aboutAutoSplitWidget)
+ self.iconLabel = QtWidgets.QLabel(aboutAutoSplitWidget)
self.iconLabel.setGeometry(QtCore.QRect(190, 17, 62, 71))
self.iconLabel.setObjectName(_fromUtf8("iconLabel"))
self.retranslateUi(aboutAutoSplitWidget)
- QtCore.QObject.connect(self.okButton, QtCore.SIGNAL(_fromUtf8("clicked()")), aboutAutoSplitWidget.close)
+ self.okButton.clicked.connect(aboutAutoSplitWidget.close)
QtCore.QMetaObject.connectSlotsByName(aboutAutoSplitWidget)
def retranslateUi(self, aboutAutoSplitWidget):
@@ -69,8 +69,8 @@ def retranslateUi(self, aboutAutoSplitWidget):
if __name__ == "__main__":
import sys
- app = QtGui.QApplication(sys.argv)
- aboutAutoSplitWidget = QtGui.QWidget()
+ app = QtWidgets.QApplication(sys.argv)
+ aboutAutoSplitWidget = QtWidgets.QWidget()
ui = Ui_aboutAutoSplitWidget()
ui.setupUi(aboutAutoSplitWidget)
aboutAutoSplitWidget.show()
diff --git a/src/capture_windows.py b/src/capture_windows.py
index 843e2522..7e3d928e 100644
--- a/src/capture_windows.py
+++ b/src/capture_windows.py
@@ -1,4 +1,3 @@
-
from ctypes import windll
from ctypes.wintypes import LONG, RECT
from win32 import win32gui
diff --git a/src/design.py b/src/design.py
index eba9c843..353c5dfc 100644
--- a/src/design.py
+++ b/src/design.py
@@ -2,11 +2,11 @@
# Form implementation generated from reading ui file 'design.ui'
#
-# Created by: PyQt4 UI code generator 4.11.4
+# Created by: PyQt5 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
-from PyQt4 import QtCore, QtGui
+from PyQt5 import QtCore, QtGui, QtWidgets
try:
_fromUtf8 = QtCore.QString.fromUtf8
@@ -15,18 +15,18 @@ def _fromUtf8(s):
return s
try:
- _encoding = QtGui.QApplication.UnicodeUTF8
+ _encoding = QtWidgets.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
- return QtGui.QApplication.translate(context, text, disambig, _encoding)
+ return QtWidgets.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
- return QtGui.QApplication.translate(context, text, disambig)
+ return QtWidgets.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(612, 490)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
@@ -38,262 +38,262 @@ def setupUi(self, MainWindow):
MainWindow.setWindowIcon(icon)
MainWindow.setWhatsThis(_fromUtf8(""))
MainWindow.setLayoutDirection(QtCore.Qt.LeftToRight)
- self.centralwidget = QtGui.QWidget(MainWindow)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
- self.splitimagefolderLabel = QtGui.QLabel(self.centralwidget)
+ self.splitimagefolderLabel = QtWidgets.QLabel(self.centralwidget)
self.splitimagefolderLabel.setGeometry(QtCore.QRect(90, 13, 91, 16))
self.splitimagefolderLabel.setObjectName(_fromUtf8("splitimagefolderLabel"))
- self.splitimagefolderLineEdit = QtGui.QLineEdit(self.centralwidget)
+ self.splitimagefolderLineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.splitimagefolderLineEdit.setGeometry(QtCore.QRect(187, 11, 247, 20))
self.splitimagefolderLineEdit.setReadOnly(True)
self.splitimagefolderLineEdit.setObjectName(_fromUtf8("splitimagefolderLineEdit"))
- self.browseButton = QtGui.QPushButton(self.centralwidget)
+ self.browseButton = QtWidgets.QPushButton(self.centralwidget)
self.browseButton.setGeometry(QtCore.QRect(443, 9, 75, 24))
self.browseButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.browseButton.setObjectName(_fromUtf8("browseButton"))
- self.xLabel = QtGui.QLabel(self.centralwidget)
+ self.xLabel = QtWidgets.QLabel(self.centralwidget)
self.xLabel.setGeometry(QtCore.QRect(25, 139, 7, 16))
self.xLabel.setObjectName(_fromUtf8("xLabel"))
- self.liveimageCheckBox = QtGui.QCheckBox(self.centralwidget)
+ self.liveimageCheckBox = QtWidgets.QCheckBox(self.centralwidget)
self.liveimageCheckBox.setEnabled(True)
self.liveimageCheckBox.setGeometry(QtCore.QRect(125, 253, 121, 17))
self.liveimageCheckBox.setChecked(True)
self.liveimageCheckBox.setTristate(False)
self.liveimageCheckBox.setObjectName(_fromUtf8("liveimageCheckBox"))
- self.loopCheckBox = QtGui.QCheckBox(self.centralwidget)
+ self.loopCheckBox = QtWidgets.QCheckBox(self.centralwidget)
self.loopCheckBox.setEnabled(True)
self.loopCheckBox.setGeometry(QtCore.QRect(500, 314, 121, 17))
self.loopCheckBox.setChecked(False)
self.loopCheckBox.setTristate(False)
self.loopCheckBox.setObjectName(_fromUtf8("loopCheckBox"))
- self.autostartonresetCheckBox = QtGui.QCheckBox(self.centralwidget)
+ self.autostartonresetCheckBox = QtWidgets.QCheckBox(self.centralwidget)
self.autostartonresetCheckBox.setEnabled(True)
self.autostartonresetCheckBox.setGeometry(QtCore.QRect(500, 344, 121, 17))
self.autostartonresetCheckBox.setChecked(False)
self.autostartonresetCheckBox.setTristate(False)
self.autostartonresetCheckBox.setObjectName(_fromUtf8("autostartonresetCheckBox"))
- self.selectregionButton = QtGui.QPushButton(self.centralwidget)
+ self.selectregionButton = QtWidgets.QPushButton(self.centralwidget)
self.selectregionButton.setGeometry(QtCore.QRect(5, 67, 101, 23))
self.selectregionButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.selectregionButton.setObjectName(_fromUtf8("selectregionButton"))
- self.similaritythresholdLabel = QtGui.QLabel(self.centralwidget)
- self.similaritythresholdLabel.setGeometry(QtCore.QRect(10, 374, 91, 22))
+ self.similaritythresholdLabel = QtWidgets.QLabel(self.centralwidget)
+ self.similaritythresholdLabel.setGeometry(QtCore.QRect(10, 378, 91, 16))
self.similaritythresholdLabel.setObjectName(_fromUtf8("similaritythresholdLabel"))
- self.similaritythresholdDoubleSpinBox = QtGui.QDoubleSpinBox(self.centralwidget)
+ self.similaritythresholdDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.similaritythresholdDoubleSpinBox.setGeometry(QtCore.QRect(160, 383, 64, 22))
self.similaritythresholdDoubleSpinBox.setMaximum(1.0)
self.similaritythresholdDoubleSpinBox.setSingleStep(0.01)
self.similaritythresholdDoubleSpinBox.setProperty("value", 0.9)
self.similaritythresholdDoubleSpinBox.setObjectName(_fromUtf8("similaritythresholdDoubleSpinBox"))
- self.startautosplitterButton = QtGui.QPushButton(self.centralwidget)
+ self.startautosplitterButton = QtWidgets.QPushButton(self.centralwidget)
self.startautosplitterButton.setGeometry(QtCore.QRect(506, 425, 101, 31))
self.startautosplitterButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.startautosplitterButton.setObjectName(_fromUtf8("startautosplitterButton"))
- self.resetButton = QtGui.QPushButton(self.centralwidget)
+ self.resetButton = QtWidgets.QPushButton(self.centralwidget)
self.resetButton.setGeometry(QtCore.QRect(506, 385, 101, 31))
self.resetButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.resetButton.setObjectName(_fromUtf8("resetButton"))
- self.undosplitButton = QtGui.QPushButton(self.centralwidget)
+ self.undosplitButton = QtWidgets.QPushButton(self.centralwidget)
self.undosplitButton.setGeometry(QtCore.QRect(477, 251, 61, 21))
self.undosplitButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.undosplitButton.setObjectName(_fromUtf8("undosplitButton"))
- self.skipsplitButton = QtGui.QPushButton(self.centralwidget)
+ self.skipsplitButton = QtWidgets.QPushButton(self.centralwidget)
self.skipsplitButton.setGeometry(QtCore.QRect(541, 251, 61, 21))
self.skipsplitButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.skipsplitButton.setObjectName(_fromUtf8("skipsplitButton"))
- self.pauseLabel = QtGui.QLabel(self.centralwidget)
- self.pauseLabel.setGeometry(QtCore.QRect(10, 420, 111, 22))
+ self.pauseLabel = QtWidgets.QLabel(self.centralwidget)
+ self.pauseLabel.setGeometry(QtCore.QRect(10, 420, 140, 16))
self.pauseLabel.setObjectName(_fromUtf8("pauseLabel"))
- self.checkfpsButton = QtGui.QPushButton(self.centralwidget)
+ self.checkfpsButton = QtWidgets.QPushButton(self.centralwidget)
self.checkfpsButton.setGeometry(QtCore.QRect(5, 225, 51, 21))
self.checkfpsButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.checkfpsButton.setObjectName(_fromUtf8("checkfpsButton"))
- self.fpsLabel = QtGui.QLabel(self.centralwidget)
+ self.fpsLabel = QtWidgets.QLabel(self.centralwidget)
self.fpsLabel.setGeometry(QtCore.QRect(87, 225, 20, 20))
self.fpsLabel.setObjectName(_fromUtf8("fpsLabel"))
- self.showlivesimilarityCheckBox = QtGui.QCheckBox(self.centralwidget)
+ self.showlivesimilarityCheckBox = QtWidgets.QCheckBox(self.centralwidget)
self.showlivesimilarityCheckBox.setEnabled(True)
self.showlivesimilarityCheckBox.setGeometry(QtCore.QRect(10, 330, 111, 17))
self.showlivesimilarityCheckBox.setChecked(True)
self.showlivesimilarityCheckBox.setTristate(False)
self.showlivesimilarityCheckBox.setObjectName(_fromUtf8("showlivesimilarityCheckBox"))
- self.showhighestsimilarityCheckBox = QtGui.QCheckBox(self.centralwidget)
+ self.showhighestsimilarityCheckBox = QtWidgets.QCheckBox(self.centralwidget)
self.showhighestsimilarityCheckBox.setEnabled(True)
self.showhighestsimilarityCheckBox.setGeometry(QtCore.QRect(10, 351, 131, 17))
self.showhighestsimilarityCheckBox.setChecked(True)
self.showhighestsimilarityCheckBox.setTristate(False)
self.showhighestsimilarityCheckBox.setObjectName(_fromUtf8("showhighestsimilarityCheckBox"))
- self.livesimilarityLabel = QtGui.QLabel(self.centralwidget)
+ self.livesimilarityLabel = QtWidgets.QLabel(self.centralwidget)
self.livesimilarityLabel.setGeometry(QtCore.QRect(160, 332, 46, 13))
self.livesimilarityLabel.setText(_fromUtf8(""))
self.livesimilarityLabel.setObjectName(_fromUtf8("livesimilarityLabel"))
- self.highestsimilarityLabel = QtGui.QLabel(self.centralwidget)
+ self.highestsimilarityLabel = QtWidgets.QLabel(self.centralwidget)
self.highestsimilarityLabel.setGeometry(QtCore.QRect(160, 353, 46, 13))
self.highestsimilarityLabel.setText(_fromUtf8(""))
self.highestsimilarityLabel.setObjectName(_fromUtf8("highestsimilarityLabel"))
- self.splitLabel = QtGui.QLabel(self.centralwidget)
+ self.splitLabel = QtWidgets.QLabel(self.centralwidget)
self.splitLabel.setGeometry(QtCore.QRect(249, 317, 61, 16))
self.splitLabel.setObjectName(_fromUtf8("splitLabel"))
- self.resetLabel = QtGui.QLabel(self.centralwidget)
+ self.resetLabel = QtWidgets.QLabel(self.centralwidget)
self.resetLabel.setGeometry(QtCore.QRect(249, 341, 61, 16))
self.resetLabel.setObjectName(_fromUtf8("resetLabel"))
- self.skiptsplitLabel = QtGui.QLabel(self.centralwidget)
+ self.skiptsplitLabel = QtWidgets.QLabel(self.centralwidget)
self.skiptsplitLabel.setGeometry(QtCore.QRect(249, 367, 50, 16))
self.skiptsplitLabel.setObjectName(_fromUtf8("skiptsplitLabel"))
- self.undosplitLabel = QtGui.QLabel(self.centralwidget)
+ self.undosplitLabel = QtWidgets.QLabel(self.centralwidget)
self.undosplitLabel.setGeometry(QtCore.QRect(249, 393, 61, 16))
self.undosplitLabel.setObjectName(_fromUtf8("undosplitLabel"))
- self.pausehotkeyLabel = QtGui.QLabel(self.centralwidget)
+ self.pausehotkeyLabel = QtWidgets.QLabel(self.centralwidget)
self.pausehotkeyLabel.setGeometry(QtCore.QRect(249, 418, 61, 16))
self.pausehotkeyLabel.setObjectName(_fromUtf8("undosplitLabel"))
- self.splitLineEdit = QtGui.QLineEdit(self.centralwidget)
+ self.splitLineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.splitLineEdit.setGeometry(QtCore.QRect(316, 314, 81, 20))
self.splitLineEdit.setReadOnly(True)
self.splitLineEdit.setObjectName(_fromUtf8("splitLineEdit"))
- self.undosplitLineEdit = QtGui.QLineEdit(self.centralwidget)
+ self.undosplitLineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.undosplitLineEdit.setGeometry(QtCore.QRect(316, 391, 81, 20))
self.undosplitLineEdit.setFocusPolicy(QtCore.Qt.StrongFocus)
self.undosplitLineEdit.setReadOnly(True)
self.undosplitLineEdit.setObjectName(_fromUtf8("undosplitLineEdit"))
- self.skipsplitLineEdit = QtGui.QLineEdit(self.centralwidget)
+ self.skipsplitLineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.skipsplitLineEdit.setGeometry(QtCore.QRect(316, 365, 81, 20))
self.skipsplitLineEdit.setReadOnly(True)
self.skipsplitLineEdit.setObjectName(_fromUtf8("skipsplitLineEdit"))
- self.resetLineEdit = QtGui.QLineEdit(self.centralwidget)
+ self.resetLineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.resetLineEdit.setGeometry(QtCore.QRect(316, 339, 81, 20))
self.resetLineEdit.setReadOnly(True)
self.resetLineEdit.setObjectName(_fromUtf8("resetLineEdit"))
- self.pausehotkeyLineEdit = QtGui.QLineEdit(self.centralwidget)
+ self.pausehotkeyLineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.pausehotkeyLineEdit.setGeometry(QtCore.QRect(316, 416, 81, 20))
self.pausehotkeyLineEdit.setReadOnly(True)
self.pausehotkeyLineEdit.setObjectName(_fromUtf8("pausehotkeyLineEdit"))
- self.setsplithotkeyButton = QtGui.QPushButton(self.centralwidget)
+ self.setsplithotkeyButton = QtWidgets.QPushButton(self.centralwidget)
self.setsplithotkeyButton.setGeometry(QtCore.QRect(409, 314, 71, 21))
self.setsplithotkeyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.setsplithotkeyButton.setObjectName(_fromUtf8("setsplithotkeyButton"))
- self.setresethotkeyButton = QtGui.QPushButton(self.centralwidget)
+ self.setresethotkeyButton = QtWidgets.QPushButton(self.centralwidget)
self.setresethotkeyButton.setGeometry(QtCore.QRect(410, 339, 71, 21))
self.setresethotkeyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.setresethotkeyButton.setObjectName(_fromUtf8("setresethotkeyButton"))
- self.setskipsplithotkeyButton = QtGui.QPushButton(self.centralwidget)
+ self.setskipsplithotkeyButton = QtWidgets.QPushButton(self.centralwidget)
self.setskipsplithotkeyButton.setGeometry(QtCore.QRect(410, 365, 71, 21))
self.setskipsplithotkeyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.setskipsplithotkeyButton.setObjectName(_fromUtf8("setskipsplithotkeyButton"))
- self.setundosplithotkeyButton = QtGui.QPushButton(self.centralwidget)
+ self.setundosplithotkeyButton = QtWidgets.QPushButton(self.centralwidget)
self.setundosplithotkeyButton.setGeometry(QtCore.QRect(410, 391, 71, 21))
self.setundosplithotkeyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.setundosplithotkeyButton.setObjectName(_fromUtf8("setundosplithotkeyButton"))
- self.setpausehotkeyButton = QtGui.QPushButton(self.centralwidget)
+ self.setpausehotkeyButton = QtWidgets.QPushButton(self.centralwidget)
self.setpausehotkeyButton.setGeometry(QtCore.QRect(410, 416, 71, 21))
self.setpausehotkeyButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.setpausehotkeyButton.setObjectName(_fromUtf8("setpausehotkeyButton"))
- self.line_live_bottom = QtGui.QFrame(self.centralwidget)
+ self.line_live_bottom = QtWidgets.QFrame(self.centralwidget)
self.line_live_bottom.setGeometry(QtCore.QRect(111, 247, 240, 2))
- self.line_live_bottom.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_live_bottom.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_live_bottom.setLineWidth(1)
- self.line_live_bottom.setFrameShape(QtGui.QFrame.HLine)
+ self.line_live_bottom.setFrameShape(QtWidgets.QFrame.HLine)
self.line_live_bottom.setObjectName(_fromUtf8("line_live_bottom"))
- self.line_live_top = QtGui.QFrame(self.centralwidget)
+ self.line_live_top = QtWidgets.QFrame(self.centralwidget)
self.line_live_top.setGeometry(QtCore.QRect(111, 68, 240, 2))
- self.line_live_top.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_live_top.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_live_top.setLineWidth(1)
- self.line_live_top.setFrameShape(QtGui.QFrame.HLine)
+ self.line_live_top.setFrameShape(QtWidgets.QFrame.HLine)
self.line_live_top.setObjectName(_fromUtf8("line_live_top"))
- self.line_live_right = QtGui.QFrame(self.centralwidget)
+ self.line_live_right = QtWidgets.QFrame(self.centralwidget)
self.line_live_right.setGeometry(QtCore.QRect(349, 69, 2, 180))
- self.line_live_right.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_live_right.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_live_right.setLineWidth(1)
- self.line_live_right.setFrameShape(QtGui.QFrame.VLine)
+ self.line_live_right.setFrameShape(QtWidgets.QFrame.VLine)
self.line_live_right.setObjectName(_fromUtf8("line_live_right"))
- self.line_left = QtGui.QFrame(self.centralwidget)
+ self.line_left = QtWidgets.QFrame(self.centralwidget)
self.line_left.setGeometry(QtCore.QRect(234, 296, 2, 163))
- self.line_left.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_left.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_left.setLineWidth(1)
- self.line_left.setFrameShape(QtGui.QFrame.VLine)
+ self.line_left.setFrameShape(QtWidgets.QFrame.VLine)
self.line_left.setObjectName(_fromUtf8("line_left"))
- self.line_live_left = QtGui.QFrame(self.centralwidget)
+ self.line_live_left = QtWidgets.QFrame(self.centralwidget)
self.line_live_left.setGeometry(QtCore.QRect(110, 69, 2, 180))
- self.line_live_left.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_live_left.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_live_left.setLineWidth(1)
- self.line_live_left.setFrameShape(QtGui.QFrame.VLine)
+ self.line_live_left.setFrameShape(QtWidgets.QFrame.VLine)
self.line_live_left.setObjectName(_fromUtf8("line_live_left"))
- self.line_split_left = QtGui.QFrame(self.centralwidget)
+ self.line_split_left = QtWidgets.QFrame(self.centralwidget)
self.line_split_left.setGeometry(QtCore.QRect(360, 69, 2, 180))
- self.line_split_left.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_split_left.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_split_left.setLineWidth(1)
- self.line_split_left.setFrameShape(QtGui.QFrame.VLine)
+ self.line_split_left.setFrameShape(QtWidgets.QFrame.VLine)
self.line_split_left.setObjectName(_fromUtf8("line_split_left"))
- self.line_split_right = QtGui.QFrame(self.centralwidget)
+ self.line_split_right = QtWidgets.QFrame(self.centralwidget)
self.line_split_right.setGeometry(QtCore.QRect(599, 69, 2, 180))
- self.line_split_right.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_split_right.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_split_right.setLineWidth(1)
- self.line_split_right.setFrameShape(QtGui.QFrame.VLine)
+ self.line_split_right.setFrameShape(QtWidgets.QFrame.VLine)
self.line_split_right.setObjectName(_fromUtf8("line_split_right"))
- self.line_split_top = QtGui.QFrame(self.centralwidget)
+ self.line_split_top = QtWidgets.QFrame(self.centralwidget)
self.line_split_top.setGeometry(QtCore.QRect(361, 68, 240, 2))
- self.line_split_top.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_split_top.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_split_top.setLineWidth(1)
- self.line_split_top.setFrameShape(QtGui.QFrame.HLine)
+ self.line_split_top.setFrameShape(QtWidgets.QFrame.HLine)
self.line_split_top.setObjectName(_fromUtf8("line_split_top"))
- self.line_split_bottom = QtGui.QFrame(self.centralwidget)
+ self.line_split_bottom = QtWidgets.QFrame(self.centralwidget)
self.line_split_bottom.setGeometry(QtCore.QRect(361, 247, 240, 2))
- self.line_split_bottom.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_split_bottom.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_split_bottom.setLineWidth(1)
- self.line_split_bottom.setFrameShape(QtGui.QFrame.HLine)
+ self.line_split_bottom.setFrameShape(QtWidgets.QFrame.HLine)
self.line_split_bottom.setObjectName(_fromUtf8("line_split_bottom"))
- self.timerglobalhotkeysLabel = QtGui.QLabel(self.centralwidget)
+ self.timerglobalhotkeysLabel = QtWidgets.QLabel(self.centralwidget)
self.timerglobalhotkeysLabel.setGeometry(QtCore.QRect(313, 293, 101, 20))
self.timerglobalhotkeysLabel.setObjectName(_fromUtf8("timerglobalhotkeysLabel"))
- self.line_right = QtGui.QFrame(self.centralwidget)
+ self.line_right = QtWidgets.QFrame(self.centralwidget)
self.line_right.setGeometry(QtCore.QRect(489, 296, 2, 163))
- self.line_right.setFrameShadow(QtGui.QFrame.Plain)
+ self.line_right.setFrameShadow(QtWidgets.QFrame.Plain)
self.line_right.setLineWidth(1)
- self.line_right.setFrameShape(QtGui.QFrame.VLine)
+ self.line_right.setFrameShape(QtWidgets.QFrame.VLine)
self.line_right.setObjectName(_fromUtf8("line_right"))
- self.liveImage = QtGui.QLabel(self.centralwidget)
+ self.liveImage = QtWidgets.QLabel(self.centralwidget)
self.liveImage.setGeometry(QtCore.QRect(111, 69, 240, 180))
self.liveImage.setText(_fromUtf8(""))
self.liveImage.setObjectName(_fromUtf8("liveImage"))
- self.currentSplitImage = QtGui.QLabel(self.centralwidget)
+ self.currentSplitImage = QtWidgets.QLabel(self.centralwidget)
self.currentSplitImage.setGeometry(QtCore.QRect(361, 69, 240, 180))
self.currentSplitImage.setText(_fromUtf8(""))
self.currentSplitImage.setObjectName(_fromUtf8("currentSplitImage"))
- self.currentsplitimageLabel = QtGui.QLabel(self.centralwidget)
+ self.currentsplitimageLabel = QtWidgets.QLabel(self.centralwidget)
self.currentsplitimageLabel.setAlignment(QtCore.Qt.AlignCenter)
self.currentsplitimageLabel.setGeometry(QtCore.QRect(370, 50, 221, 20))
self.currentsplitimageLabel.setObjectName(_fromUtf8("currentsplitimageLabel"))
- self.imageloopLabel = QtGui.QLabel(self.centralwidget)
+ self.imageloopLabel = QtWidgets.QLabel(self.centralwidget)
self.imageloopLabel.setGeometry(QtCore.QRect(362, 251, 108, 20))
self.imageloopLabel.setObjectName(_fromUtf8("Image Loop #:"))
- self.widthLabel = QtGui.QLabel(self.centralwidget)
+ self.widthLabel = QtWidgets.QLabel(self.centralwidget)
self.widthLabel.setGeometry(QtCore.QRect(14, 177, 31, 16))
self.widthLabel.setObjectName(_fromUtf8("widthLabel"))
- self.heightLabel = QtGui.QLabel(self.centralwidget)
+ self.heightLabel = QtWidgets.QLabel(self.centralwidget)
self.heightLabel.setGeometry(QtCore.QRect(68, 177, 31, 16))
self.heightLabel.setObjectName(_fromUtf8("heightLabel"))
- self.fpsvalueLabel = QtGui.QLabel(self.centralwidget)
+ self.fpsvalueLabel = QtWidgets.QLabel(self.centralwidget)
self.fpsvalueLabel.setGeometry(QtCore.QRect(58, 225, 26, 20))
self.fpsvalueLabel.setText(_fromUtf8(""))
self.fpsvalueLabel.setObjectName(_fromUtf8("fpsvalueLabel"))
- self.widthSpinBox = QtGui.QSpinBox(self.centralwidget)
+ self.widthSpinBox = QtWidgets.QSpinBox(self.centralwidget)
self.widthSpinBox.setGeometry(QtCore.QRect(6, 193, 44, 22))
self.widthSpinBox.setMinimum(1)
self.widthSpinBox.setMaximum(10000)
self.widthSpinBox.setProperty("value", 640)
self.widthSpinBox.setObjectName(_fromUtf8("widthSpinBox"))
- self.heightSpinBox = QtGui.QSpinBox(self.centralwidget)
+ self.heightSpinBox = QtWidgets.QSpinBox(self.centralwidget)
self.heightSpinBox.setGeometry(QtCore.QRect(62, 193, 44, 22))
self.heightSpinBox.setMinimum(1)
self.heightSpinBox.setMaximum(10000)
self.heightSpinBox.setProperty("value", 480)
self.heightSpinBox.setObjectName(_fromUtf8("heightSpinBox"))
- self.captureregionLabel = QtGui.QLabel(self.centralwidget)
+ self.captureregionLabel = QtWidgets.QLabel(self.centralwidget)
self.captureregionLabel.setGeometry(QtCore.QRect(192, 50, 81, 16))
self.captureregionLabel.setObjectName(_fromUtf8("captureregionLabel"))
- self.fpslimitLabel = QtGui.QLabel(self.centralwidget)
+ self.fpslimitLabel = QtWidgets.QLabel(self.centralwidget)
self.fpslimitLabel.setGeometry(QtCore.QRect(8, 251, 51, 16))
self.fpslimitLabel.setObjectName(_fromUtf8("fpslimitLabel"))
- self.fpslimitSpinBox = QtGui.QDoubleSpinBox(self.centralwidget)
+ self.fpslimitSpinBox = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.fpslimitSpinBox.setGeometry(QtCore.QRect(62, 248, 44, 22))
self.fpslimitSpinBox.setPrefix(_fromUtf8(""))
self.fpslimitSpinBox.setDecimals(0)
@@ -302,59 +302,59 @@ def setupUi(self, MainWindow):
self.fpslimitSpinBox.setSingleStep(1.0)
self.fpslimitSpinBox.setProperty("value", 60.0)
self.fpslimitSpinBox.setObjectName(_fromUtf8("fpslimitSpinBox"))
- self.currentsplitimagefileLabel = QtGui.QLabel(self.centralwidget)
+ self.currentsplitimagefileLabel = QtWidgets.QLabel(self.centralwidget)
self.currentsplitimagefileLabel.setGeometry(QtCore.QRect(362, 271, 237, 20))
self.currentsplitimagefileLabel.setText(_fromUtf8(""))
self.currentsplitimagefileLabel.setAlignment(QtCore.Qt.AlignCenter)
self.currentsplitimagefileLabel.setObjectName(_fromUtf8("currentsplitimagefileLabel"))
- self.takescreenshotButton = QtGui.QPushButton(self.centralwidget)
+ self.takescreenshotButton = QtWidgets.QPushButton(self.centralwidget)
self.takescreenshotButton.setGeometry(QtCore.QRect(250, 251, 91, 21))
self.takescreenshotButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.takescreenshotButton.setObjectName(_fromUtf8("takescreenshotButton"))
- self.xSpinBox = QtGui.QSpinBox(self.centralwidget)
+ self.xSpinBox = QtWidgets.QSpinBox(self.centralwidget)
self.xSpinBox.setGeometry(QtCore.QRect(6, 154, 44, 22))
self.xSpinBox.setReadOnly(False)
- self.xSpinBox.setButtonSymbols(QtGui.QAbstractSpinBox.UpDownArrows)
+ self.xSpinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.UpDownArrows)
self.xSpinBox.setMinimum(0)
self.xSpinBox.setMaximum(999999999)
self.xSpinBox.setSingleStep(1)
self.xSpinBox.setProperty("value", 0)
self.xSpinBox.setObjectName(_fromUtf8("xSpinBox"))
- self.ySpinBox = QtGui.QSpinBox(self.centralwidget)
+ self.ySpinBox = QtWidgets.QSpinBox(self.centralwidget)
self.ySpinBox.setGeometry(QtCore.QRect(62, 154, 44, 22))
self.ySpinBox.setReadOnly(False)
- self.ySpinBox.setButtonSymbols(QtGui.QAbstractSpinBox.UpDownArrows)
+ self.ySpinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.UpDownArrows)
self.ySpinBox.setMinimum(0)
self.ySpinBox.setMaximum(999999999)
self.ySpinBox.setProperty("value", 0)
self.ySpinBox.setObjectName(_fromUtf8("ySpinBox"))
- self.yLabel = QtGui.QLabel(self.centralwidget)
+ self.yLabel = QtWidgets.QLabel(self.centralwidget)
self.yLabel.setGeometry(QtCore.QRect(81, 139, 7, 16))
self.yLabel.setObjectName(_fromUtf8("yLabel"))
- self.comparisonmethodComboBox = QtGui.QComboBox(self.centralwidget)
+ self.comparisonmethodComboBox = QtWidgets.QComboBox(self.centralwidget)
self.comparisonmethodComboBox.setGeometry(QtCore.QRect(143, 299, 81, 22))
self.comparisonmethodComboBox.setObjectName(_fromUtf8("comparisonmethodComboBox"))
self.comparisonmethodComboBox.addItem(_fromUtf8(""))
self.comparisonmethodComboBox.addItem(_fromUtf8(""))
self.comparisonmethodComboBox.addItem(_fromUtf8(""))
- self.pauseDoubleSpinBox = QtGui.QDoubleSpinBox(self.centralwidget)
+ self.pauseDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.pauseDoubleSpinBox.setGeometry(QtCore.QRect(160, 425, 64, 22))
self.pauseDoubleSpinBox.setMaximum(999999999.0)
self.pauseDoubleSpinBox.setSingleStep(1.0)
self.pauseDoubleSpinBox.setProperty("value", 10.0)
self.pauseDoubleSpinBox.setObjectName(_fromUtf8("pauseDoubleSpinBox"))
- self.comparisonmethodLabel = QtGui.QLabel(self.centralwidget)
+ self.comparisonmethodLabel = QtWidgets.QLabel(self.centralwidget)
self.comparisonmethodLabel.setGeometry(QtCore.QRect(10, 300, 101, 16))
self.comparisonmethodLabel.setObjectName(_fromUtf8("comparisonmethodLabel"))
- self.alignregionButton = QtGui.QPushButton(self.centralwidget)
+ self.alignregionButton = QtWidgets.QPushButton(self.centralwidget)
self.alignregionButton.setGeometry(QtCore.QRect(5, 92, 101, 23))
self.alignregionButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.alignregionButton.setObjectName(_fromUtf8("alignregionButton"))
- self.groupDummySplitsCheckBox = QtGui.QCheckBox(self.centralwidget)
+ self.groupDummySplitsCheckBox = QtWidgets.QCheckBox(self.centralwidget)
self.groupDummySplitsCheckBox.setGeometry(QtCore.QRect(252, 440, 230, 17))
self.groupDummySplitsCheckBox.setChecked(False)
self.groupDummySplitsCheckBox.setObjectName(_fromUtf8("groupDummySplitsCheckBox"))
- self.selectwindowButton = QtGui.QPushButton(self.centralwidget)
+ self.selectwindowButton = QtWidgets.QPushButton(self.centralwidget)
self.selectwindowButton.setGeometry(QtCore.QRect(5, 117, 101, 23))
self.selectwindowButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.selectwindowButton.setObjectName(_fromUtf8("selectwindowButton"))
@@ -429,23 +429,23 @@ def setupUi(self, MainWindow):
self.groupDummySplitsCheckBox.raise_()
self.selectwindowButton.raise_()
MainWindow.setCentralWidget(self.centralwidget)
- self.menuBar = QtGui.QMenuBar(MainWindow)
+ self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 612, 21))
self.menuBar.setObjectName(_fromUtf8("menuBar"))
- self.menuFile = QtGui.QMenu(self.menuBar)
+ self.menuFile = QtWidgets.QMenu(self.menuBar)
self.menuFile.setObjectName(_fromUtf8("menuFile"))
- self.menuHelp = QtGui.QMenu(self.menuBar)
+ self.menuHelp = QtWidgets.QMenu(self.menuBar)
self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
MainWindow.setMenuBar(self.menuBar)
- self.actionView_Help = QtGui.QAction(MainWindow)
+ self.actionView_Help = QtWidgets.QAction(MainWindow)
self.actionView_Help.setObjectName(_fromUtf8("actionView_Help"))
- self.actionAbout = QtGui.QAction(MainWindow)
+ self.actionAbout = QtWidgets.QAction(MainWindow)
self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
- self.actionSave_Settings = QtGui.QAction(MainWindow)
+ self.actionSave_Settings = QtWidgets.QAction(MainWindow)
self.actionSave_Settings.setObjectName(_fromUtf8("actionSave_Settings"))
- self.actionSave_Settings_As = QtGui.QAction(MainWindow)
+ self.actionSave_Settings_As = QtWidgets.QAction(MainWindow)
self.actionSave_Settings_As.setObjectName(_fromUtf8("actionSave_Settings_As"))
- self.actionLoad_Settings = QtGui.QAction(MainWindow)
+ self.actionLoad_Settings = QtWidgets.QAction(MainWindow)
self.actionLoad_Settings.setObjectName(_fromUtf8("actionLoad_Settings"))
self.menuHelp.addAction(self.actionView_Help)
self.menuHelp.addAction(self.actionAbout)
@@ -533,8 +533,8 @@ def retranslateUi(self, MainWindow):
if __name__ == "__main__":
import sys
- app = QtGui.QApplication(sys.argv)
- MainWindow = QtGui.QMainWindow()
+ app = QtWidgets.QApplication(sys.argv)
+ MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
diff --git a/src/error_messages.py b/src/error_messages.py
index f2a7fdd2..4eb88bd4 100644
--- a/src/error_messages.py
+++ b/src/error_messages.py
@@ -1,22 +1,22 @@
# Error messages
-from PyQt4 import QtGui
+from PyQt5 import QtWidgets
def splitImageDirectoryError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("No split image folder is selected.")
msgBox.exec_()
def splitImageDirectoryNotFoundError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("The Split Image Folder does not exist.")
msgBox.exec_()
def imageTypeError(self, image):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText(
'"' + image + '" is not a valid image file or the full image file path contains a special character.')
@@ -24,86 +24,86 @@ def imageTypeError(self, image):
def regionError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("No region is selected or the Capture Region window is not open. Select a region or load settings while the Capture Region window is open.")
msgBox.exec_()
def regionSizeError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Width and height cannot be 0. Please select a larger region.")
msgBox.exec_()
def splitHotkeyError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("No split hotkey has been set.")
msgBox.exec_()
def pauseHotkeyError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Your split image folder contains an image filename with a pause flag {p}, but no pause hotkey is set.")
msgBox.exec_()
def alignRegionImageTypeError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("File not a valid image file")
msgBox.exec_()
def alignmentNotMatchedError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("No area in capture region matched reference image. Alignment failed.")
msgBox.exec_()
def multipleResetImagesError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Only one image with the keyword \"reset\" is allowed.")
msgBox.exec_()
def resetHotkeyError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Your split image folder contains a reset image, but no reset hotkey is set.")
msgBox.exec_()
def dummySplitsError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText(
"Group dummy splits when undoing/skipping cannot be checked if any split image has a loop parameter greater than 1")
msgBox.exec_()
def oldVersionSettingsFileError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Old version settings file detected. This version allows settings files from v1.3 and above.")
msgBox.exec_()
def invalidSettingsError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Invalid settings file.")
msgBox.exec_()
def noSettingsFileOnOpenError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("No settings file found. One can be loaded on open if placed in the same folder as AutoSplit.exe")
msgBox.exec_()
def tooManySettingsFilesOnOpenError(self):
- msgBox = QtGui.QMessageBox()
+ msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Error')
msgBox.setText("Too many settings files found. Only one can be loaded on open if placed in the same folder as AutoSplit.exe")
msgBox.exec_()
diff --git a/src/menu_bar.py b/src/menu_bar.py
index 598f8435..c65e7d5c 100644
--- a/src/menu_bar.py
+++ b/src/menu_bar.py
@@ -1,9 +1,9 @@
import os
-from PyQt4 import QtGui
+from PyQt5 import QtWidgets
import about
# About Window
-class AboutWidget(QtGui.QWidget, about.Ui_aboutAutoSplitWidget):
+class AboutWidget(QtWidgets.QWidget, about.Ui_aboutAutoSplitWidget):
def __init__(self):
super(AboutWidget, self).__init__()
self.setupUi(self)
diff --git a/src/resources_rc.py b/src/resources_rc.py
index 0ded678b..2abb2a55 100644
--- a/src/resources_rc.py
+++ b/src/resources_rc.py
@@ -2,11 +2,11 @@
# Resource object code
#
-# Created by: The Resource Compiler for PyQt4 (Qt v4.8.7)
+# Created by: The Resource Compiler for PyQt5 (Qt v4.8.7)
#
# WARNING! All changes made in this file will be lost!
-from PyQt4 import QtCore
+from PyQt5 import QtCore
qt_resource_data = b"\
\x00\x00\x3b\x7f\
diff --git a/src/screen_region.py b/src/screen_region.py
index 6de9b2b6..44d24af3 100644
--- a/src/screen_region.py
+++ b/src/screen_region.py
@@ -1,4 +1,4 @@
-from PyQt4 import QtGui, QtCore, QtTest
+from PyQt5 import QtCore, QtGui, QtTest, QtWidgets
from win32 import win32gui
import capture_windows
import ctypes
@@ -124,7 +124,7 @@ def alignRegion(self):
return
# This is the image used for aligning the capture region
# to the best fit for the user.
- template_filename = str(QtGui.QFileDialog.getOpenFileName(self, "Select Reference Image", "",
+ template_filename = str(QtWidgets.QFileDialog.getOpenFileName(self, "Select Reference Image", "",
"Image Files (*.png *.jpg *.jpeg *.jpe *.jp2 *.bmp *.tiff *.tif *.dib *.webp *.pbm *.pgm *.ppm *.sr *.ras)"))
# return if the user presses cancel
@@ -200,7 +200,7 @@ def alignRegion(self):
# widget to select a window and obtain its bounds
-class SelectWindowWidget(QtGui.QWidget):
+class SelectWindowWidget(QtWidgets.QWidget):
def __init__(self):
super(SelectWindowWidget, self).__init__()
user32 = ctypes.windll.user32
@@ -231,7 +231,7 @@ def mouseReleaseEvent(self, event):
# Widget for dragging screen region
# https://github.com/harupy/snipping-tool
-class SelectRegionWidget(QtGui.QWidget):
+class SelectRegionWidget(QtWidgets.QWidget):
def __init__(self):
super(SelectRegionWidget, self).__init__()
user32 = ctypes.windll.user32
@@ -254,7 +254,7 @@ def __init__(self):
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.setWindowOpacity(0.5)
- QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
+ QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.show()
@@ -274,7 +274,7 @@ def mouseMoveEvent(self, event):
self.update()
def mouseReleaseEvent(self, event):
- QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
+ QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.close()
# The coordinates are pulled relative to the top left of the set geometry,
diff --git a/src/settings_file.py b/src/settings_file.py
index ef8d3006..e43575ab 100644
--- a/src/settings_file.py
+++ b/src/settings_file.py
@@ -1,9 +1,10 @@
from win32 import win32gui
-from PyQt4 import QtGui
+from PyQt5 import QtWidgets
import keyboard
import pickle
import glob
+
def getSaveSettingsValues(self):
# get values to be able to save settings
self.x = self.xSpinBox.value()
@@ -103,7 +104,7 @@ def saveSettings(self):
def saveSettingsAs(self):
# user picks save destination
- self.save_settings_file_path = str(QtGui.QFileDialog.getSaveFileName(self, "Save Settings As", "", "PKL (*.pkl)"))
+ self.save_settings_file_path = str(QtWidgets.QFileDialog.getSaveFileName(self, "Save Settings As", "", "PKL (*.pkl)"))
#if user cancels save destination window, don't save settings
if self.save_settings_file_path == '':
@@ -163,7 +164,7 @@ def loadSettings(self):
self.load_settings_file_path = self.settings_files[0]
else:
- self.load_settings_file_path = str(QtGui.QFileDialog.getOpenFileName(self, "Load Settings", "", "PKL (*.pkl)"))
+ self.load_settings_file_path = str(QtWidgets.QFileDialog.getOpenFileName(self, "Load Settings", "", "PKL (*.pkl)"))
#
if self.load_settings_file_path == '':
From 0025d13f2e2e325219877531d42cfc79cc5c6156 Mon Sep 17 00:00:00 2001
From: Avasam
Date: Tue, 9 Nov 2021 22:36:56 -0500
Subject: [PATCH 7/8] Migrate to PyQt6
---
.vscode/settings.json | 6 +-
README.md | 40 +-
res/about.ui | 49 +-
res/btn_donateCC_LG.png | Bin 0 -> 2701 bytes
res/design.ui | 161 +-
example1.5.0.gif => res/example1.5.0.gif | Bin
icon.ico => res/icon.ico | Bin
.../mask_example_image.PNG | Bin
res/resources.qrc | 2 +-
scripts/build.bat | 2 +-
scripts/compile_resources.bat | 2 -
scripts/designer.exe.lnk | Bin 0 -> 2237 bytes
src/AutoSplit.py | 123 +-
src/about.py | 85 +-
src/compare.py | 4 +-
src/design.py | 560 +-
src/error_messages.py | 126 +-
src/icon.ico | Bin 33490 -> 0 bytes
src/menu_bar.py | 7 +-
src/resources_rc.py | 4819 +++++++----------
src/screen_region.py | 65 +-
src/settings_file.py | 23 +-
22 files changed, 2625 insertions(+), 3449 deletions(-)
create mode 100644 res/btn_donateCC_LG.png
rename example1.5.0.gif => res/example1.5.0.gif (100%)
rename icon.ico => res/icon.ico (100%)
rename mask_example_image.PNG => res/mask_example_image.PNG (100%)
create mode 100644 scripts/designer.exe.lnk
delete mode 100644 src/icon.ico
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3e2705c9..5cbde4f7 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -41,5 +41,9 @@
"trailing-spaces.trimOnSave": true,
"trailing-spaces.syntaxIgnore": [
"markdown"
- ]
+ ],
+ "files.associations": {
+ "*.qrc": "xml",
+ "*.ui": "xml"
+ },
}
diff --git a/README.md b/README.md
index 97dcf4d6..7c71fcf0 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,32 @@
-#
AutoSplit
+#
AutoSplit
-This program compares split images to a capture region of any window (OBS, xsplit, etc.) and automatically hits your split hotkey when there is a match. It can be used in tandem with any speedrun timer that accepts hotkeys (LiveSplit, wsplit, etc.). The purpose of this program is to remove the need to manually press your split hotkey and also increase the accuracy of your splits.
+This program compares split images to a capture region of any window (OBS, xsplit, etc.) and automatically hits your split hotkey when there is a match. It can be used in tandem with any speedrun timer that accepts hotkeys (LiveSplit, wsplit, etc.). The purpose of this program is to remove the need to manually press your split hotkey and also increase the accuracy of your splits.
-
+
# TUTORIAL
## DOWNLOAD AND OPEN
### Compatability
+
- Windows 7, 10, and 11.
### Building
-- Read [requirements.txt](/scripts/requirements.txt) for information on how to run/build the python code
+
+- Read [requirements.txt](/scripts/requirements.txt) for information on how to install, run and build the python code.
### Opening the program
-- Download the [latest version](https://github.com/austinryan/Auto-Split/releases)
+
+- Download the [latest version](/Toufool/Auto-Split/releases)
- Extract the file and open AutoSplit.exe.
### Building
+
- Read [requirements.txt](/requirements.txt) for information on how to run/build the python code (this is not required for normal use).
## Split Image Folder
+
- Supported image file types: .png, .jpg, .jpeg, .bmp, and [more](https://docs.opencv.org/3.0-beta/modules/imgcodecs/doc/reading_and_writing_images.html#imread).
- Images can be any size.
- Images are matched in alphanumerical order.
@@ -30,6 +35,7 @@ This program compares split images to a capture region of any window (OBS, xspli
- Images can be created using Print Screen, [Snipping Tool](https://support.microsoft.com/en-us/help/4027213/windows-10-open-snipping-tool-and-take-a-screenshot), or AutoSplit's Take Screenshot button.
## Capture Region
+
- This is the region that your split images are compared to. Usually, this is going to be the full game screen.
- Click "Select Region"
- Click and drag to form a rectangle over the region you want to capture.
@@ -40,11 +46,13 @@ This program compares split images to a capture region of any window (OBS, xspli
- You can save a screenshot of the capture region to your split image folder using the Take Screenshot button.
## Max FPS
+
- Calculates the maximum comparison rate of the capture region to split images. This value will likely be much higher than needed, so it is highly recommended to limit your FPS depending on the frame rate of the game you are capturing.
## OPTIONS
### Comparison Method
+
- There are three comparison methods to choose from: L2 Norm, Histograms, and pHash.
- L2 Norm: This method finds the difference between each pixel, squares it, and sums it over the entire image and takes the square root. This is very fast but is a problem if your image is high frequency. Any translational movement or rotation can cause similarity to be very different.
- Histograms: An explanation on Histograms comparison can be found [here](https://mpatacchiola.github.io/blog/2016/11/12/the-simplest-classifier-histogram-intersection.html). This is a great method to use if you are using several masked images.
@@ -52,21 +60,27 @@ This program compares split images to a capture region of any window (OBS, xspli
- Note: v1.0 used L2 Norm.
### Show Live Similarity
+
- Displays the live similarity between the capture region and the current split image. This number is between 0 and 1, with 1 being a perfect match.
### Show Highest Similarity
+
- Shows the highest similarity between the capture region and current split image.
### Similarity Threshold
+
- When the live similarity goes above this value, the program hits your split hotkey and moves to the next split image.
### Pause Time
+
- Time in seconds that the program stops comparison after a split. Useful for if you have two of the same split images in a row and want to avoid double-splitting. Also useful for reducing CPU usage.
### Delay Time
+
- Time in milliseconds that the program waits before hitting the split hotkey for that specific split.
### Custom Split Image Settings
+
- Each split image can have different thresholds, pause times, delay split times, loop amounts, and can be flagged.
- These settings are handled in the image's filename.
- Custom thresholds are place between parenthesis `()` in the filename and the custom thresholds checkbox must be checked. All images must have a custom threshold if the box is checked.
@@ -86,20 +100,24 @@ This program compares split images to a capture region of any window (OBS, xspli
- `004_SplitName(0.9)_[10]_#3500#_@3@_{b}.png` is the fourth split image with a threshold of 0.9, pause time of 10 seconds, delay split time of 3.5 seconds, will loop 3 times, and will split when similarity is below the threshold rather than above.
### How to Create a Masked Image
+
The best way to create a masked image is to set your capture region as the entire game screen, take a screenshot, and use a program like [paint.net](https://www.getpaint.net/) to "erase" (make transparent) everything you don't want the program to compare. More on how to creating images with transparency using paint.net can be found in [this tutorial](https://www.youtube.com/watch?v=v53kkUYFVn8). The last thing you need to do is add {m} to the filename. For visualization, here is what the capture region compared to a masked split image looks like if you would want to split on "Shine Get!" text in Super Mario Sunshine:
-
+
### Reset image
+
You can have one (and only one) image with the keyword `reset` in its name. AutoSplit will press the reset button when it finds this image. This image will only be used for resets and it will not be tied to any split. You can set a probability and pause time for it. A custom threshold MUST be applied to this image. The pause time is the amount of seconds AutoSplit will wait before checking for the reset image once the run starts. Also the image can be masked, for example: `Reset_(0.95)_[10]_{m}.png`.
### Timer Global Hotkeys
+
- Click "Set Hotkey" on each hotkey to set the hotkeys to AutoSplit. The Start / Split hotkey and Pause hotkey must be the same as the one used in your preferred timer program in order for the splitting/pausing to work properly.
- Make sure that Global Hotkeys are enabled in your speedrun timer.
- All of these actions can also be handled by their corresponding buttons.
- Note that pressing your Pause Hotkey does not serve any function in AutoSplit itself and is strictly used for the Pause flag.
### Group dummy splits when undoing / skipping
+
If this option is disabled, AutoSplit will not account for dummy splits when undoing/skipping. Meaning it will cycle through ths splits normally even if they are dummy splits (this was the normal behavior in versions 1.2.0 and older).
If it is enabled, AutoSplit will group dummy splits together with a real split when undoing/skipping. This basically allows you to tie one or more dummy splits to a real split to keep it in sync with LiveSplit/wsplit.
@@ -117,11 +135,13 @@ In this situation you would have only 3 splits in LiveSplit/wsplit (even though
Please note this option cannot currently be used if you have any loop parameter `@@` greater than 1 in any image.
### Loop Split Images
+
If this option is enabled, when the last split meets the threshold and splits, AutoSplit will loop back to the first split image and continue comparisons.
If this option is disabled, when the last split meets the threshold and splits, AutoSplit will stop running comparisons.
This option does not loop single, specific images. See the Custom Split Image Settings section above for this feature.
### Auto Start On Reset
+
If this option is enabled, when the reset hotkey is hit, the reset button is pressed, or the reset split image meets its threshold, AutoSplit will reset and automatically start again back at the first split image.
If this option is disabled, when the reset hotkey is hit, the reset button is pressed, or the reset split image meets its threshold, AutoSplit will stop running comparisons.
@@ -133,27 +153,31 @@ If this option is disabled, when the reset hotkey is hit, the reset button is pr
- If you are upgrading to Windows 11, it's possible that save files may not transfer perfectly. You may need to readjust or reselect your Capture Region, for example.
## Known Limitations
+
- For many games, it will be difficult to find a split image for the last split of the run.
- The window of the capture region cannot be minimized.
## Known Issues
+
- Using numpad number keys when numlock is on does not split correctly. Either avoid using numpad or turn numlock off to avoid this issue.
- LiveSplit and wsplit will not split correctly if you are holding shift, ctrl, or alt when a match occurs.
- Numlock on keys are linked to numlock-off keys. For example, if you set your reset hotkey to 2, you can hit arrow down and it will reset and vice versa.
## Resources
+
- Still need help? [Open an issue](https://github.com/Toufool/Auto-Split/issues)
- Join the [AutoSplit Discord](https://discord.gg/Qcbxv9y)
-
## Credits
-- https://github.com/harupy/ for the snipping tool code that I used to integrate into the autosplitter.
+
+- for the snipping tool code that I used to integrate into the autosplitter.
- [amaringos](https://twitter.com/amaringos) for the icon.
- [ZanasoBayncuh](https://twitter.com/ZanasoBayncuh) for motivating me to start this project back up and for all of the time spent testing and suggesting improvements.
- [Avasam](https://twitter.com/Avasam06) for their continued work on making an incredible amount of improvements and changes to AutoSplit while I have not had the time/motivation to do so.
- Created by [Toufool](https://twitter.com/Toufool) and [Faschz](https://twitter.com/faschz).
## Donate
+
If you enjoy using the program, please consider donating. Thank you!
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=BYRHQG69YRHBA&item_name=AutoSplit+development¤cy_code=USD&source=url)
diff --git a/res/about.ui b/res/about.ui
index d247f2c3..f5efddb9 100644
--- a/res/about.ui
+++ b/res/about.ui
@@ -6,20 +6,20 @@
0
0
- 276
- 249
+ 264
+ 250
- 276
- 249
+ 264
+ 250
- 276
- 249
+ 264
+ 250
@@ -32,10 +32,10 @@
- 190
+ 180
220
- 71
- 21
+ 75
+ 24
@@ -47,12 +47,12 @@
10
44
- 151
- 16
+ 161
+ 32
- <html><head/><body><p>Created by <a href="https://twitter.com/toufool"><span style=" text-decoration: underline; color:#0000ff;">Toufool</span></a> and <a href="https://twitter.com/faschz"><span style=" text-decoration: underline; color:#0000ff;">Faschz</span></a></p></body></html>
+ <html><head/><body><p>Created by <a href="https://twitter.com/toufool"><span style=" text-decoration: underline; color:#0000ff;">Toufool</span></a> and <a href="https://twitter.com/faschz"><span style=" text-decoration: underline; color:#0000ff;">Faschz</span></a><br/>Maintained by <a href="https://twitter.com/Avasam06"><span style=" text-decoration: underline; color:#0000ff;">Avasam</span></a></p></body></html>
@@ -60,39 +60,42 @@
10
21
- 71
+ 161
16
- Version: 1.2.0
+ Version:
- 46
+ 30
95
- 191
- 41
+ 204
+ 32
If you enjoy using this program, please
- consider donating. Thank you!
+consider donating. Thank you!
+
+
+ Qt::AlignCenter
- 52
- 127
- 171
- 91
+ 60
+ 150
+ 147
+ 47
- <html><head/><body><p><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=BYRHQG69YRHBA&item_name=AutoSplit+development¤cy_code=USD&source=url"><img src=":/resources/donatebutton.png"/></p></body></html>
+ <html><head/><body><p><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=BYRHQG69YRHBA&item_name=AutoSplit+development&currency_code=USD&source=url"><img src=":/resources/btn_donateCC_LG.png"/></a></p></body></html>
Qt::AlignCenter
diff --git a/res/btn_donateCC_LG.png b/res/btn_donateCC_LG.png
new file mode 100644
index 0000000000000000000000000000000000000000..3abf57adcc5e4e742612e8604ccde1732c5cf7bf
GIT binary patch
literal 2701
zcmV;83Uc*{P)vs|I%pt$W8XZK=i>#Swj;5000F91TQ2CYf%>KwKVg(
zHxLL0925oCq%U||8;58f`oA~juroz543%;r%bYE>izwQsFr$4W;jA)aOBST2sl2@tVkDtp)B9_p$^a`~e*BED-jd8~?K(drl6MIcg}3*Z{Nl0jTK!q26h)>2ka8
ze!=lsd_rk8O?)SCeKmW9;O6V_
z^7ixf`SSGj`~3Xt0UQ2d0sD9e|Ee90VyRby&I6m*23lyC#OvpQ-pvCQR
zpWt7T+gOd-*xTKZn4H7N%D20{)YsUUqNmZz#{SEn{k?|Mz_7l<#e|QQ^6~NWt+?h4
zE@=}x03}yWiIXcfc*M!rn4P|(r^QQDi|6R@0~K2Ofetx^#{iPck;d?fx9NqfuhiMnx_5E#Q
zOnm@jvw!l#Ub~)c&-?ZLexKhDg1C$DjEqS>pX8I;@HMabI`8A>IK6((*ob#GXSSTZz8^KQ*>t8EVo{5nmJl!!e;hE}9;u%te!_yPR
zGc{vi;!90CW}5zRs(Jx!{_=vY$B~GG=${a(5%RoBn32W
zNwc6}ENDt-$tNvXB%}c?FcS(naeQW=CPD8el14+J8i+=eEoqGqOCvzqBATXxIyjh{bItgG
zO$5`M$;u4Te0xMO*~6?DZl6s=xOA>saec0+c;tKoy^{
zx6_*hv9l8}Rt9kKtr&rwK|~ssVPY`Q{oK#}{2$^t{LVb&1P30bIO0qYBQ#H07T>$L
zs9(9lH{9GuJ^~pz(%r+u)6>h_dlb&21Tost=gv4e_G%g~zB6NdunGQ8LaeW^?^r+4
zxN+w2uMh;A@FVi`_4oJn3m89Pe1HpnjZG6ZCUzYoeE5n}BoVbBIy!pcB1p_)oY;rJ6c-yW7DvV>OowN2;>5T_
zt%>rVDUnE?SdtVJ6qFn!>M^MgL@#}ASx9I|$a0M-C3VG$m1(O|Q&zd9r=?_MWM)d!
zvPP*)iSweO#w3X6C5TsNi?gRkCd8>tQxk|aIXRLUxj4&J$-{NZU;F&Jbp?g%H*72@
zDijwMZ_=9B&G^(?mMqzdQ7`nE#!B#k7q@Mj6&e~E@{)_%^zy{i)MwIC-BzsHE-R6x
zNlVMJGRjq^9Xobb>~gHwz2}v^`(Dl44-KjuJwj!AjW`e;eelrhkmd5lK#GZU#=R?4
zR8=dg6*Wplbye-6!)v4NFdezoMETU@I(95&W$FsI)RL6ClJxql
z@bXM)gt~Y8D=Xi8cxS^~Zzm-kZ>TJ;tZb~9SD`Y!v*6tmCl;POx#*-k_7t>Eo~<(F
zE7vR6pH}1*C~CyjN@a0&e&y$b=;$CTO>=IP<_Y)Z-Y^me!QjQaZ0c4=vQ
zY34=TyUEk?^7aSrcznvG%d2;c&ac>A_2`vPu<6s!qAy(iytt^NqoXrM-g-*jrZ$PI
zzbHy9Qq~kfjT8mNiYo1l!`wi&Yz#ozf>l3RwaA?A^WuY$xbgxg%
zo}Qk~GMOw>b}bVM6;Yp2USB4?$gviDxA(@)<0{klCvtLf4&~;y#Adg}CdSF-2^v$c
z>l1Wo>{vfaDEdLfBHi@~AMo=-E&;g#O-O6<^70C=tCN*pD-CbQy{nhDx0l7=Zd!e5
z-;J|3HKrf0g6XH++~SU(<(;jaF`ZHUnVPz~x*EIAcQrP`L!+*#$<_6|t7{kBe$krB
zywvfAUFBD8Ze25fyL90Np&RF|9dx>*{n0c9y>P78Yah4V!+^HL;CAas{%EsoWa}
z?{SlK(zCaK=MMlS-NZ>!nRZ>daP{ive-;%fi{y~Sozr1$?{^Po@r{KIm%VKd#&6>E
z?7{8fI1zYL(Mg
0
0
- 619
+ 640
490
@@ -18,13 +18,13 @@
- 619
+ 640
490
- 619
+ 640
490
@@ -45,9 +45,9 @@
- 90
+ 80
13
- 91
+ 98
16
@@ -61,7 +61,7 @@
187
11
247
- 20
+ 22
@@ -103,10 +103,10 @@
- 125
+ 120
253
- 121
- 17
+ 129
+ 20
@@ -139,9 +139,9 @@
10
- 378
- 91
- 21
+ 380
+ 102
+ 32
@@ -153,7 +153,7 @@ Default value
160
- 383
+ 390
64
22
@@ -171,7 +171,7 @@ Default value
- 505
+ 510
425
101
31
@@ -187,7 +187,7 @@ Default value
- 505
+ 510
385
101
31
@@ -205,8 +205,8 @@ Default value
477
250
- 61
- 21
+ 75
+ 24
@@ -219,10 +219,10 @@ Default value
- 541
+ 560
250
- 61
- 21
+ 75
+ 24
@@ -237,8 +237,8 @@ Default value
10
420
- 111
- 21
+ 112
+ 32
@@ -251,7 +251,7 @@ Default value
5
225
- 51
+ 53
21
@@ -283,8 +283,8 @@ Default value
10
330
- 111
- 17
+ 124
+ 20
@@ -305,8 +305,8 @@ Default value
10
351
- 131
- 17
+ 145
+ 20
@@ -325,7 +325,7 @@ Default value
160
332
46
- 13
+ 16
@@ -338,7 +338,7 @@ Default value
160
353
46
- 13
+ 16
@@ -348,9 +348,9 @@ Default value
- 249
+ 240
317
- 61
+ 58
16
@@ -361,9 +361,9 @@ Default value
- 249
+ 240
341
- 61
+ 28
16
@@ -374,9 +374,9 @@ Default value
- 250
+ 240
367
- 50
+ 48
16
@@ -387,9 +387,9 @@ Default value
- 249
+ 240
393
- 61
+ 55
16
@@ -400,7 +400,7 @@ Default value
- 316
+ 310
314
81
20
@@ -413,7 +413,7 @@ Default value
- 316
+ 310
391
81
20
@@ -429,7 +429,7 @@ Default value
- 316
+ 310
365
81
20
@@ -442,7 +442,7 @@ Default value
- 316
+ 310
339
81
20
@@ -455,7 +455,7 @@ Default value
- 410
+ 400
314
71
21
@@ -471,7 +471,7 @@ Default value
- 410
+ 400
339
71
21
@@ -487,7 +487,7 @@ Default value
- 410
+ 400
365
71
21
@@ -503,7 +503,7 @@ Default value
- 410
+ 400
391
71
21
@@ -576,7 +576,7 @@ Default value
- 234
+ 230
296
2
163
@@ -690,10 +690,10 @@ Default value
- 313
+ 310
293
- 101
- 20
+ 113
+ 16
@@ -703,7 +703,7 @@ Default value
- 489
+ 500
296
2
163
@@ -910,8 +910,8 @@ Default value
250
251
- 91
- 21
+ 92
+ 24
@@ -990,9 +990,9 @@ Default value
- 143
+ 133
299
- 81
+ 91
22
@@ -1016,7 +1016,7 @@ Default value
160
- 425
+ 430
64
22
@@ -1035,8 +1035,8 @@ Default value
10
- 300
- 101
+ 303
+ 110
16
@@ -1063,10 +1063,10 @@ Default value
- 252
+ 240
443
- 240
- 17
+ 261
+ 20
@@ -1092,11 +1092,11 @@ Default value
Select Window
-
+
362
- 251
+ 252
108
20
@@ -1108,9 +1108,9 @@ Default value
- 250
+ 240
418
- 61
+ 31
16
@@ -1121,7 +1121,7 @@ Default value
- 316
+ 310
416
82
20
@@ -1137,7 +1137,7 @@ Default value
- 410
+ 400
416
71
21
@@ -1156,10 +1156,10 @@ Default value
- 500
+ 510
314
- 121
- 17
+ 117
+ 20
@@ -1172,16 +1172,13 @@ Default value
false
-
-
- true
-
+
- 500
+ 510
344
- 121
- 17
+ 126
+ 20
@@ -1258,20 +1255,20 @@ Default value
alignregionButton
groupDummySplitsCheckBox
selectwindowButton
- currentsplitimageLabel_2
+ imageloopLabel
pausehotkeyLabel
pausehotkeyLineEdit
setpausehotkeyButton
loopCheckBox
- loopCheckBox_2
+ autostartonresetCheckBox
@@ -18,13 +18,13 @@
- 640
+ 632
490
- 640
+ 632
490
@@ -45,8 +45,8 @@
- 80
- 13
+ 20
+ 12
98
16
@@ -58,9 +58,9 @@
- 187
- 11
- 247
+ 130
+ 10
+ 411
22
@@ -71,7 +71,7 @@
- 443
+ 539
9
75
24
@@ -152,7 +152,7 @@ Default value
- 160
+ 150
390
64
22
@@ -171,9 +171,9 @@ Default value
- 510
+ 500
425
- 101
+ 121
31
@@ -187,9 +187,9 @@ Default value
- 510
+ 500
385
- 101
+ 121
31
@@ -203,9 +203,9 @@ Default value
- 477
+ 480
250
- 75
+ 71
24
@@ -221,7 +221,7 @@ Default value
560
250
- 75
+ 61
24
@@ -348,7 +348,7 @@ Default value
- 240
+ 230
317
58
16
@@ -361,7 +361,7 @@ Default value
- 240
+ 230
341
28
16
@@ -374,7 +374,7 @@ Default value
- 240
+ 230
367
48
16
@@ -387,7 +387,7 @@ Default value
- 240
+ 230
393
55
16
@@ -400,7 +400,7 @@ Default value
- 310
+ 300
314
81
20
@@ -413,7 +413,7 @@ Default value
- 310
+ 300
391
81
20
@@ -429,7 +429,7 @@ Default value
- 310
+ 300
365
81
20
@@ -442,7 +442,7 @@ Default value
- 310
+ 300
339
81
20
@@ -455,7 +455,7 @@ Default value
- 400
+ 390
314
71
21
@@ -471,7 +471,7 @@ Default value
- 400
+ 390
339
71
21
@@ -487,7 +487,7 @@ Default value
- 400
+ 390
365
71
21
@@ -503,7 +503,7 @@ Default value
- 400
+ 390
391
71
21
@@ -516,67 +516,10 @@ Default value
Set Hotkey
-
-
-
- 111
- 247
- 240
- 2
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
-
-
- 111
- 68
- 240
- 2
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
-
-
- 349
- 69
- 2
- 180
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Vertical
-
-
- 230
+ 220
296
2
163
@@ -592,105 +535,10 @@ Default value
Qt::Vertical
-
-
-
- 110
- 69
- 2
- 180
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Vertical
-
-
-
-
-
- 360
- 69
- 2
- 180
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Vertical
-
-
-
-
-
- 599
- 69
- 2
- 180
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Vertical
-
-
-
-
-
- 361
- 68
- 240
- 2
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
-
-
- 361
- 247
- 240
- 2
-
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Horizontal
-
-
- 310
+ 300
293
113
16
@@ -703,7 +551,7 @@ Default value
- 500
+ 490
296
2
163
@@ -722,12 +570,15 @@ Default value
- 111
+ 120
69
240
180
+
+ QFrame::Box
+
@@ -735,12 +586,15 @@ Default value
- 361
+ 380
69
240
180
+
+ QFrame::Box
+
@@ -748,9 +602,9 @@ Default value
- 430
+ 450
50
- 221
+ 102
16
@@ -838,9 +692,9 @@ Default value
- 192
+ 200
50
- 81
+ 82
16
@@ -892,9 +746,9 @@ Default value
- 362
- 271
- 237
+ 380
+ 270
+ 241
20
@@ -992,7 +846,7 @@ Default value
133
299
- 91
+ 81
22
@@ -1015,7 +869,7 @@ Default value
- 160
+ 150
430
64
22
@@ -1063,7 +917,7 @@ Default value
- 240
+ 230
443
261
20
@@ -1095,7 +949,7 @@ Default value
- 362
+ 380
252
108
20
@@ -1108,7 +962,7 @@ Default value
- 240
+ 230
418
31
16
@@ -1121,9 +975,9 @@ Default value
- 310
+ 300
416
- 82
+ 81
20
@@ -1137,7 +991,7 @@ Default value
- 400
+ 390
416
71
21
@@ -1156,8 +1010,8 @@ Default value
- 510
- 314
+ 500
+ 340
117
20
@@ -1175,8 +1029,8 @@ Default value
- 510
- 344
+ 500
+ 360
126
20
@@ -1191,6 +1045,35 @@ Default value
false
+
+
+
+ 500
+ 300
+ 121
+ 31
+
+
+
+ Qt::NoFocus
+
+
+ Reload Start Image
+
+
+
+
+
+ 120
+ 270
+ 241
+ 16
+
+
+
+ Start image:
+
+
splitimagefolderLabel
splitimagefolderLineEdit
browseButton
@@ -1222,15 +1105,7 @@ Default value
setresethotkeyButton
setskipsplithotkeyButton
setundosplithotkeyButton
- line_live_bottom
- line_live_top
- line_live_right
line_left
- line_live_left
- line_split_left
- line_split_right
- line_split_top
- line_split_bottom
timerglobalhotkeysLabel
line_right
currentsplitimageLabel
@@ -1261,13 +1136,15 @@ Default value
setpausehotkeyButton
loopCheckBox
autostartonresetCheckBox
+ startImageReloadButton
+ startImageLabel