Skip to content

Commit

Permalink
User Profile, Revamped settings, Start image fixes & __auto_splitter …
Browse files Browse the repository at this point in the history
…method refactor
  • Loading branch information
Avasam committed Sep 3, 2022
1 parent 51574ac commit 1283103
Show file tree
Hide file tree
Showing 12 changed files with 481 additions and 488 deletions.
7 changes: 3 additions & 4 deletions src/AutoControlledWorker.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from PyQt6 import QtCore

import error_messages
import settings_file as settings
import user_profile

if TYPE_CHECKING:
from AutoSplit import AutoSplit
Expand All @@ -25,8 +25,7 @@ def run(self):
break
except EOFError:
continue
# TODO: "AutoSplit Integration" needs to call this and wait instead of outright killing the app.
# For now this can only used in a Development environment
# This is for use in a Development environment
if line == "kill":
self.autosplit.closeEvent()
break
Expand All @@ -40,7 +39,7 @@ def run(self):
self.autosplit.reset_signal.emit()
elif line.startswith("settings"):
# Allow for any split character between "settings" and the path
settings.load_settings(self.autosplit, line[9:])
user_profile.load_settings(self.autosplit, line[9:])
# TODO: Not yet implemented in AutoSplit Integration
# elif line == 'pause':
# self.pause_signal.emit()
365 changes: 189 additions & 176 deletions src/AutoSplit.py

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions src/AutoSplitImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class AutoSplitImage():
flags: int
loops: int
image_type: ImageType
bytes: Optional[cv2.ndarray] = None
byte_array: Optional[cv2.ndarray] = None
mask: Optional[cv2.ndarray] = None
# This value is internal, check for mask instead
_has_transparency: bool
_has_transparency = False
# These values should be overriden by Defaults if None. Use getters instead
__delay_time: Optional[float] = None
__comparison_method: Optional[int] = None
Expand Down Expand Up @@ -73,7 +73,7 @@ def get_pause_time(self, default: Union[AutoSplit, float]):

def get_similarity_threshold(self, default: Union[AutoSplit, float]):
"""
Get image's similarity threashold or fallback to the default value from spinbox
Get image's similarity threshold or fallback to the default value from spinbox
"""
default_value = default \
if isinstance(default, float) \
Expand Down Expand Up @@ -101,7 +101,7 @@ def __init__(self, path: str):
def __read_image_bytes(self, path: str):
image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
if image is None:
self.bytes = None
self.byte_array = None
error_messages.image_type(path)
return

Expand All @@ -117,7 +117,7 @@ def __read_image_bytes(self, path: str):
elif image.shape[2] == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)

self.bytes = image
self.byte_array = image

def check_flag(self, flag: int):
return self.flags & flag == flag
Expand All @@ -131,13 +131,13 @@ def compare_with_capture(
Compare image with capture using image's comparison method. Falls back to combobox
"""

if self.bytes is None or capture is None:
if self.byte_array is None or capture is None:
return 0.0
comparison_method = self.__get_comparison_method(default)
if comparison_method == 0:
return compare_l2_norm(self.bytes, capture, self.mask)
return compare_l2_norm(self.byte_array, capture, self.mask)
if comparison_method == 1:
return compare_histograms(self.bytes, capture, self.mask)
return compare_histograms(self.byte_array, capture, self.mask)
if comparison_method == 2:
return compare_phash(self.bytes, capture, self.mask)
return compare_phash(self.byte_array, capture, self.mask)
return 0.0
33 changes: 15 additions & 18 deletions src/capture_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import ctypes
import ctypes.wintypes
from dataclasses import dataclass
from typing import Optional, cast
from typing import Optional, TypedDict, cast

import cv2
import numpy as np
Expand All @@ -18,13 +17,11 @@
PW_RENDERFULLCONTENT = 0x00000002


@dataclass
class Region():
def __init__(self, x: int, y: int, width: int, height: int):
self.x = x
self.y = y
self.width = width
self.height = height
class Region(TypedDict):
x: int
y: int
width: int
height: int


def capture_region(hwnd: int, selection: Region, print_window: bool):
Expand All @@ -48,26 +45,26 @@ def capture_region(hwnd: int, selection: Region, print_window: bool):

compatible_dc = dc_object.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(dc_object, selection.width, selection.height)
bitmap.CreateCompatibleBitmap(dc_object, selection["width"], selection["height"])
compatible_dc.SelectObject(bitmap)
compatible_dc.BitBlt((0, 0),
(selection.width, selection.height),
dc_object,
(selection.x, selection.y),
win32con.SRCCOPY)
compatible_dc.BitBlt(
(0, 0),
(selection["width"], selection["height"]),
dc_object,
(selection["x"], selection["y"]),
win32con.SRCCOPY)
except (win32ui.error, pywintypes.error):
return None

image = np.frombuffer(cast(bytes, bitmap.GetBitmapBits(True)), dtype="uint8")
image.shape = (selection.height, selection.width, 4)
image.shape = (selection["height"], selection["width"], 4)

try:
dc_object.DeleteDC()
compatible_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, window_dc)
win32gui.DeleteObject(bitmap.GetHandle())
# https://github.com/kaluluosi/pywin32-stubs/issues/5
except win32ui.error: # type: ignore
except win32ui.error:
pass

return image
Expand Down
4 changes: 2 additions & 2 deletions src/compare.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Optional
from typing import Optional, cast

import cv2
import imagehash # https://github.com/JohannesBuchner/imagehash/issues/151
Expand Down Expand Up @@ -111,7 +111,7 @@ def check_if_image_has_transparency(image: cv2.ndarray):
# Check if there's a transparency channel (4th channel) and if at least one pixel is transparent (< 255)
if image.shape[2] != 4:
return False
mean: float = np.mean(image[:, :, 3])
mean = cast(float, np.mean(image[:, :, 3]))
if mean == 0:
# Non-transparent images code path is usually faster and simpler, so let's return that
return False
Expand Down
3 changes: 2 additions & 1 deletion src/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def reset_hotkey():


def old_version_settings_file():
set_text_message("Old version settings file detected. This version allows settings files from v1.3 and above.")
set_text_message(
"Old version settings file detected. This version allows settings files in .toml format. Starting from v2.0.")


def invalid_settings():
Expand Down
8 changes: 3 additions & 5 deletions src/hotkeys.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from collections.abc import Callable
from typing import TYPE_CHECKING, Literal, Optional, Union

import keyboard # https://github.com/boppreh/keyboard/issues/505
import pyautogui # https://github.com/asweigart/pyautogui/issues/645
import keyboard
import pyautogui

if TYPE_CHECKING:
from AutoSplit import AutoSplit
Expand Down Expand Up @@ -183,7 +183,6 @@ def __read_hotkey():
if keyboard_event.event_type == keyboard.KEY_UP:
break
key_name = __get_key_name(keyboard_event)
print(key_name)
# Ignore long presses
if names and names[-1] == key_name:
continue
Expand Down Expand Up @@ -245,5 +244,4 @@ def callback():

# Try to remove the previously set hotkey if there is one.
_unhook(getattr(autosplit, f"{hotkey}_hotkey"))
thread = threading.Thread(target=callback)
thread.start()
threading.Thread(target=callback).start()
52 changes: 31 additions & 21 deletions src/menu_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from simplejson.errors import JSONDecodeError

import error_messages
import settings_file as settings
from capture_windows import Region
import user_profile
from gen import about, design, resources_rc, settings as settings_ui, update_checker # noqa: F401
from hotkeys import set_hotkey

Expand Down Expand Up @@ -63,7 +62,7 @@ def open_update(self):
self.close()

def do_not_ask_me_again_state_changed(self):
settings.set_check_for_updates_on_open(
user_profile.set_check_for_updates_on_open(
self.design_window,
self.do_not_ask_again_checkbox.isChecked())

Expand Down Expand Up @@ -98,14 +97,25 @@ def check_for_updates(autosplit: AutoSplit, check_on_open: bool = False):


class __SettingsWidget(QtWidgets.QDialog, settings_ui.Ui_DialogSettings):
def __update_default_threshold(self, value: Any):
self.__set_value("default_similarity_threshold", value)
self.autosplit.table_current_image_threshold_label.setText(
f"{self.autosplit.split_image.get_similarity_threshold(self.autosplit):.2f}"
if self.autosplit.split_image
else "-")
self.autosplit.table_reset_image_threshold_label.setText(
f"{self.autosplit.reset_image.get_similarity_threshold(self.autosplit):.2f}"
if self.autosplit.reset_image
else "-")

def __set_value(self, key: str, value: Any):
self.autosplit.settings_dict[key] = value

def __init__(self, autosplit: AutoSplit):
super().__init__()
self.setupUi(self)
self.autosplit = autosplit

def set_value(key: str, value: Any):
autosplit.settings_dict[key] = value

# region Set initial values
# Hotkeys
self.split_input.setText(autosplit.settings_dict["split_hotkey"])
Expand Down Expand Up @@ -135,30 +145,29 @@ def set_value(key: str, value: Any):
self.set_pause_hotkey_button.clicked.connect(lambda: set_hotkey(self.autosplit, "pause"))

# Capture Settings
self.fps_limit_spinbox.valueChanged.connect(lambda: set_value(
self.fps_limit_spinbox.valueChanged.connect(lambda: self.__set_value(
"fps_limit",
self.fps_limit_spinbox.value()))
self.live_capture_region_checkbox.stateChanged.connect(lambda: set_value(
self.live_capture_region_checkbox.stateChanged.connect(lambda: self.__set_value(
"live_capture_region",
self.live_capture_region_checkbox.isChecked()))
self.force_print_window_checkbox.stateChanged.connect(lambda: set_value(
self.force_print_window_checkbox.stateChanged.connect(lambda: self.__set_value(
"force_print_window",
self.force_print_window_checkbox.isChecked()))

# Image Settings
self.default_comparison_method.currentIndexChanged.connect(lambda: set_value(
self.default_comparison_method.currentIndexChanged.connect(lambda: self.__set_value(
"default_comparison_method",
self.default_comparison_method.currentIndex()))
self.default_similarity_threshold_spinbox.valueChanged.connect(lambda: set_value(
"default_similarity_threshold",
self.default_similarity_threshold_spinbox.valueChanged.connect(lambda: self.__update_default_threshold(
self.default_similarity_threshold_spinbox.value()))
self.default_delay_time_spinbox.valueChanged.connect(lambda: set_value(
self.default_delay_time_spinbox.valueChanged.connect(lambda: self.__set_value(
"default_delay_time",
self.default_delay_time_spinbox.value()))
self.default_pause_time_spinbox.valueChanged.connect(lambda: set_value(
self.default_pause_time_spinbox.valueChanged.connect(lambda: self.__set_value(
"default_pause_time",
self.default_pause_time_spinbox.value()))
self.loop_splits_checkbox.stateChanged.connect(lambda: set_value(
self.loop_splits_checkbox.stateChanged.connect(lambda: self.__set_value(
"loop_splits",
self.loop_splits_checkbox.isChecked()))
# endregion
Expand All @@ -174,7 +183,7 @@ def get_default_settings_from_ui(autosplit: AutoSplit):
temp_dialog = QtWidgets.QDialog()
default_settings_dialog = settings_ui.Ui_DialogSettings()
default_settings_dialog.setupUi(temp_dialog)
default_settings: settings.SettingsDict = {
default_settings: user_profile.UserProfileDict = {
"split_hotkey": default_settings_dialog.split_input.text(),
"reset_hotkey": default_settings_dialog.reset_input.text(),
"undo_split_hotkey": default_settings_dialog.undo_split_input.text(),
Expand All @@ -191,11 +200,12 @@ def get_default_settings_from_ui(autosplit: AutoSplit):

"split_image_directory": autosplit.split_image_folder_input.text(),
"captured_window_title": "",
"capture_region": Region(
autosplit.x_spinbox.value(),
autosplit.y_spinbox.value(),
autosplit.width_spinbox.value(),
autosplit.height_spinbox.value())
"capture_region": {
"x": autosplit.x_spinbox.value(),
"y": autosplit.y_spinbox.value(),
"width": autosplit.width_spinbox.value(),
"height": autosplit.height_spinbox.value(),
}
}
del temp_dialog
return default_settings
12 changes: 6 additions & 6 deletions src/screen_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,17 @@ def align_region(autosplit: AutoSplit):

# The new region can be defined by using the min_loc point and the best_height and best_width of the template.
__set_region_values(autosplit,
left=autosplit.settings_dict["capture_region"].x + best_loc[0],
top=autosplit.settings_dict["capture_region"].y + best_loc[1],
left=autosplit.settings_dict["capture_region"]["x"] + best_loc[0],
top=autosplit.settings_dict["capture_region"]["y"] + best_loc[1],
width=best_width,
height=best_height)


def __set_region_values(autosplit: AutoSplit, left: int, top: int, width: int, height: int):
autosplit.settings_dict["capture_region"].x = left
autosplit.settings_dict["capture_region"].y = top
autosplit.settings_dict["capture_region"].width = width
autosplit.settings_dict["capture_region"].height = height
autosplit.settings_dict["capture_region"]["x"] = left
autosplit.settings_dict["capture_region"]["y"] = top
autosplit.settings_dict["capture_region"]["width"] = width
autosplit.settings_dict["capture_region"]["height"] = height

autosplit.x_spinbox.setValue(left)
autosplit.y_spinbox.setValue(top)
Expand Down
Loading

0 comments on commit 1283103

Please sign in to comment.