Skip to content

Commit

Permalink
Improve SelectWidgets
Browse files Browse the repository at this point in the history
- Add a window name based on class
- Set fixed size
- Prevent running loop leak if cancelling selection
- Allow selecting a window at position 0,0
  • Loading branch information
Avasam committed Dec 14, 2023
1 parent 989fae8 commit 8950d43
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 62 deletions.
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll": "explicit",
// Let dedicated linter (Ruff) organize imports
"source.organizeImports": false,
"source.organizeImports": "never"
},
"emeraldwalk.runonsave": {
"commands": [
Expand Down
100 changes: 40 additions & 60 deletions src/region_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from winsdk.windows.graphics.capture import GraphicsCaptureItem, GraphicsCapturePicker

import error_messages
from capture_method import Region
from utils import (
BGR_CHANNEL_COUNT,
MAXBYTE,
Expand Down Expand Up @@ -92,17 +93,14 @@ def select_region(autosplit: "AutoSplit"):

# Need to wait until the user has selected a region using the widget
# before moving on with selecting the window settings
while True:
width = selector.width()
height = selector.height()
x = selector.x()
y = selector.y()
if width > 0 and height > 0:
break
while not selector.isHidden():
QTest.qWait(1)
selection = selector.selection
del selector
if selection is None:
return # No selection done

window = getTopWindowAt(x, y)
window = getTopWindowAt(selection["x"], selection["y"])
if not window:
error_messages.region()
return
Expand All @@ -122,10 +120,10 @@ def select_region(autosplit: "AutoSplit"):
offset_y = window_y + top_bounds
__set_region_values(
autosplit,
left=x - offset_x,
top=y - offset_y,
width=width,
height=height,
x=selection["x"] - offset_x,
y=selection["y"] - offset_y,
width=selection["width"],
height=selection["height"],
)


Expand All @@ -135,15 +133,14 @@ def select_window(autosplit: "AutoSplit"):

# Need to wait until the user has selected a region using the widget before moving on with
# selecting the window settings
while True:
x = selector.x()
y = selector.y()
if x and y:
break
while not selector.isHidden():
QTest.qWait(1)
selection = selector.selection
del selector
if selection is None:
return # No selection done

window = getTopWindowAt(x, y)
window = getTopWindowAt(selection["x"], selection["y"])
if not window:
error_messages.region()
return
Expand All @@ -165,8 +162,8 @@ def select_window(autosplit: "AutoSplit"):

__set_region_values(
autosplit,
left=border_width,
top=titlebar_with_border_height,
x=border_width,
y=titlebar_with_border_height,
width=client_width,
height=client_height - border_width * 2,
)
Expand Down Expand Up @@ -218,21 +215,21 @@ 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],
x=autosplit.settings_dict["capture_region"]["x"] + best_loc[0],
y=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
def __set_region_values(autosplit: "AutoSplit", x: int, y: int, width: int, height: int):
autosplit.settings_dict["capture_region"]["x"] = x
autosplit.settings_dict["capture_region"]["y"] = y
autosplit.settings_dict["capture_region"]["width"] = width
autosplit.settings_dict["capture_region"]["height"] = height

autosplit.x_spinbox.setValue(left)
autosplit.y_spinbox.setValue(top)
autosplit.x_spinbox.setValue(x)
autosplit.y_spinbox.setValue(y)
autosplit.width_spinbox.setValue(width)
autosplit.height_spinbox.setValue(height)

Expand Down Expand Up @@ -295,28 +292,19 @@ def validate_before_parsing(autosplit: "AutoSplit", show_error: bool = True, che


class BaseSelectWidget(QtWidgets.QWidget):
_x = 0
_y = 0

@override
def x(self):
return self._x

@override
def y(self):
return self._y
selection: Region | None = None

def __init__(self):
super().__init__()
# We need to pull the monitor information to correctly draw the geometry covering all portions
# of the user's screen. These parameters create the bounding box with left, top, width, and height
self.setGeometry(
user32.GetSystemMetrics(SM_XVIRTUALSCREEN),
user32.GetSystemMetrics(SM_YVIRTUALSCREEN),
user32.GetSystemMetrics(SM_CXVIRTUALSCREEN),
user32.GetSystemMetrics(SM_CYVIRTUALSCREEN),
)
self.setWindowTitle(" ")
x = user32.GetSystemMetrics(SM_XVIRTUALSCREEN)
y = user32.GetSystemMetrics(SM_YVIRTUALSCREEN)
width = user32.GetSystemMetrics(SM_CXVIRTUALSCREEN)
height = user32.GetSystemMetrics(SM_CYVIRTUALSCREEN)
self.setGeometry(x, y, width, height)
self.setFixedSize(width, height) # Prevent move/resizing on Linux
self.setWindowTitle(type(self).__name__)
self.setWindowOpacity(0.5)
self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint)
self.show()
Expand All @@ -332,8 +320,9 @@ class SelectWindowWidget(BaseSelectWidget):

@override
def mouseReleaseEvent(self, event: QtGui.QMouseEvent):
self._x = int(event.position().x()) + self.geometry().x()
self._y = int(event.position().y()) + self.geometry().y()
x = int(event.position().x()) + self.geometry().x()
y = int(event.position().y()) + self.geometry().y()
self.selection = Region(x=x, y=y, width=0, height=0)
self.close()


Expand All @@ -343,23 +332,13 @@ class SelectRegionWidget(BaseSelectWidget):
Originated from https://github.com/harupy/snipping-tool .
"""

_right: int = 0
_bottom: int = 0
__begin = QtCore.QPoint()
__end = QtCore.QPoint()

def __init__(self):
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.CrossCursor))
super().__init__()

@override
def height(self):
return self._bottom - self._y

@override
def width(self):
return self._right - self._x

@override
def paintEvent(self, event: QtGui.QPaintEvent):
if self.__begin != self.__end:
Expand All @@ -384,11 +363,12 @@ def mouseReleaseEvent(self, event: QtGui.QMouseEvent):
if self.__begin != self.__end:
# The coordinates are pulled relative to the top left of the set geometry,
# so the added virtual screen offsets convert them back to the virtual screen coordinates
self._x = min(self.__begin.x(), self.__end.x()) + self.geometry().x()
self._y = min(self.__begin.y(), self.__end.y()) + self.geometry().y()
self._right = max(self.__begin.x(), self.__end.x()) + self.geometry().x()
self._bottom = max(self.__begin.y(), self.__end.y()) + self.geometry().y()
left = min(self.__begin.x(), self.__end.x()) + self.geometry().x()
top = min(self.__begin.y(), self.__end.y()) + self.geometry().y()
right = max(self.__begin.x(), self.__end.x()) + self.geometry().x()
bottom = max(self.__begin.y(), self.__end.y()) + self.geometry().y()

self.selection = Region(x=left, y=top, width=right - left, height=bottom - top)
self.close()

@override
Expand Down

0 comments on commit 8950d43

Please sign in to comment.