Last active
March 15, 2025 14:33
-
-
Save andrewthederp/8bb4b4f42164c14b29c1bc04260dee8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import arcade | |
import pyglet | |
import enum | |
import random | |
class DragRectType(enum.IntFlag): | |
MOVEABLE = 0 | |
RESIZE_TOP = enum.auto() | |
RESIZE_BOTTOM = enum.auto() | |
RESIZE_LEFT = enum.auto() | |
RESIZE_RIGHT = enum.auto() | |
RESIZE_TOPLEFT = enum.auto() | |
RESIZE_TOPRIGHT = enum.auto() | |
RESIZE_BOTTOMRIGHT = enum.auto() | |
RESIZE_BOTTOMLEFT = enum.auto() | |
class DragRect: | |
def __init__(self, rect: arcade.Rect, type: DragRectType, cursor: str | pyglet.window.MouseCursor = None): | |
self.type = type | |
self.left = rect.left | |
self.bottom = rect.bottom | |
self.width = rect.width | |
self.height = rect.height | |
self._cursor = cursor | |
self.color = (random.randrange(255), random.randrange(255), random.randrange(255)) # Debugging purposes... | |
@property | |
def cursor(self): | |
if isinstance(self._cursor, pyglet.window.MouseCursor): | |
return self._cursor | |
window = arcade.get_window() | |
return window.get_system_mouse_cursor(self._cursor) | |
@property | |
def rect(self): | |
return arcade.LBWH(self.left, self.bottom, self.width, self.height) | |
class PiPWindow(arcade.Window): | |
def __init__(self, minimum_size: tuple[int, int] | arcade.Vec2, *args, **kwargs): | |
super().__init__(*args, **kwargs, style=pyglet.window.Window.WINDOW_STYLE_BORDERLESS) | |
self.drag_rects = self.make_drag_rects() | |
self.minimum_size = arcade.Vec2(*minimum_size) | |
self.dragging: DragRect | None = None | |
self.last_mouse_pos: tuple[int, int] = (-1, -1) | |
self.cursor = self.get_system_mouse_cursor(None) # default cursor | |
screen = arcade.get_screens()[0] # not sure if this can cause issues with multi-moniter setups since I don't have a multi-moniter setup | |
mode = screen.get_mode() | |
self.sw, self.sh = mode.width, mode.height | |
def make_drag_rects(self) -> list[DragRect]: | |
w, h = self.size | |
margin = 10 | |
return [ | |
DragRect(rect=arcade.LBWH(0, h - margin, margin, margin), type=DragRectType.RESIZE_TOPLEFT, cursor=self.CURSOR_SIZE_UP_LEFT), | |
DragRect(rect=arcade.LBWH(margin, h - margin, w - (margin * 2), margin), type=DragRectType.RESIZE_TOP, cursor=self.CURSOR_SIZE_UP), | |
DragRect(rect=arcade.LBWH(w - margin, h - margin, margin, margin), type=DragRectType.RESIZE_TOPRIGHT, cursor=self.CURSOR_SIZE_UP_RIGHT), | |
DragRect(rect=arcade.LBWH(0, margin, margin, h - (margin * 2)), type=DragRectType.RESIZE_LEFT, cursor=self.CURSOR_SIZE_LEFT), | |
DragRect(rect=arcade.LBWH(w - margin, margin, margin, h - (margin * 2)), type=DragRectType.RESIZE_RIGHT, cursor=self.CURSOR_SIZE_RIGHT), | |
DragRect(rect=arcade.LBWH(0, 0, margin, margin), type=DragRectType.RESIZE_BOTTOMLEFT, cursor=self.CURSOR_SIZE_DOWN_LEFT), | |
DragRect(rect=arcade.LBWH(margin, 0, w - (margin * 2), margin), type=DragRectType.RESIZE_BOTTOM, cursor=self.CURSOR_SIZE_DOWN), | |
DragRect(rect=arcade.LBWH(w - margin, 0, margin, margin), type=DragRectType.RESIZE_BOTTOMRIGHT, cursor=self.CURSOR_SIZE_DOWN_RIGHT), | |
DragRect(rect=arcade.LBWH(margin, margin, w - (margin * 2), h - (margin * 2)), type=DragRectType.MOVEABLE, cursor=None) | |
] | |
def on_update(self, _): # can't use `on_mouse_drag` because shifting the screen position triggers the event (I think?) | |
cx, cy = self.get_mouse_pos() | |
for rect in self.drag_rects: | |
if rect.rect.point_in_rect((self.mouse["x"], self.mouse["y"])): | |
self.set_mouse_cursor(rect.cursor) | |
break | |
else: | |
self.set_mouse_cursor(self.cursor) | |
if self.dragging is not None: | |
x, y = self.last_mouse_pos | |
dx, dy = cx - x, cy - y | |
ww, wh = self.size | |
wx, wy = self.get_location() | |
mw, mh = self.minimum_size | |
if dx or dy: | |
match self.dragging.type: | |
case DragRectType.MOVEABLE: | |
self.set_location(int(wx + dx), int(wy + dy)) | |
case DragRectType.RESIZE_RIGHT: | |
nw = max(ww + dx, mw) | |
dx = int(nw - ww) | |
self.set_size(ww + dx, wh) | |
case DragRectType.RESIZE_BOTTOMRIGHT: | |
nw, nh = max(ww + dx, mw), max(wh + dy, mh) | |
dx, dy = int(nw - ww), int(nh - wh) | |
self.set_size(ww + dx, wh + dy) | |
case DragRectType.RESIZE_BOTTOM: | |
nh = max(wh + dy, mh) | |
dy = int(nh - wh) | |
self.set_size(ww, wh + dy) | |
case DragRectType.RESIZE_BOTTOMLEFT: | |
nw, nh = max(ww - dx, mw), max(wh + dy, mh) | |
dx, dy = -int(nw - ww), int(nh - wh) | |
self.set_size(ww - dx, wh + dy) | |
self.set_location(wx + dx, wy) | |
case DragRectType.RESIZE_LEFT: | |
nw = max(ww - dx, mw) | |
dx = -int(nw - ww) | |
self.set_size(ww - dx, wh) | |
self.set_location(wx + dx, wy) | |
case DragRectType.RESIZE_TOPLEFT: | |
nw, nh = max(ww - dx, mw), max(wh - dy, mh) | |
dx, dy = -int(nw - ww), int(wh - nh) | |
self.set_size(ww - dx, wh - dy) | |
self.set_location(wx + dx, wy + dy) | |
case DragRectType.RESIZE_TOP: | |
nh = max(wh - dy, mh) | |
dy = int(wh - nh) | |
self.set_size(ww, wh - dy) | |
self.set_location(wx, wy + dy) | |
case DragRectType.RESIZE_TOPRIGHT: | |
nw, nh = max(ww + dx, mw), max(wh - dy, mh) | |
dx, dy = int(nw - ww), int(wh - nh) | |
self.set_size(ww + dx, wh - dy) | |
self.set_location(wx, wy + dy) | |
self.last_mouse_pos = cx, cy | |
def get_mouse_pos(self): | |
"A function to get the mouse pos on the display, not the arcade window" | |
ww, wh = self.size | |
wx, wy = self.get_location() | |
mx, my = self.mouse["x"], self.mouse["y"] | |
return int(mx + wx), int(wy + (wh - my)) | |
def on_draw(self): | |
self.clear() | |
for rect in self.drag_rects: | |
arcade.draw_rect_filled(rect.rect, rect.color) | |
def on_mouse_press(self, x, y, button, _): | |
if button != arcade.MOUSE_BUTTON_LEFT: | |
return | |
for rect in self.drag_rects: | |
if rect.rect.point_in_rect((x, y)): | |
self.dragging = rect | |
return | |
def on_mouse_release(self, x, y, button, modifiers): | |
if button != arcade.MOUSE_BUTTON_LEFT: | |
return | |
self.drag_rects = self.make_drag_rects() | |
self.dragging = None | |
size = 500 * (192 / 108), 500 | |
min_size = 200 * (192 / 108), 200 | |
window = PiPWindow(min_size, *size, "PiP test") | |
window.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment