Add helper.py
This commit is contained in:
423
helper.py
Normal file
423
helper.py
Normal file
@@ -0,0 +1,423 @@
|
||||
import ctypes
|
||||
import tkinter as tk
|
||||
|
||||
|
||||
try:
|
||||
ctypes.windll.shcore.SetProcessDpiAwareness(2)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class GridOverlay:
|
||||
def __init__(
|
||||
self,
|
||||
color="#00ff66",
|
||||
line_width=2,
|
||||
mode="thirds",
|
||||
):
|
||||
self.root = tk.Tk()
|
||||
|
||||
self.root.overrideredirect(True)
|
||||
|
||||
self.root.attributes(
|
||||
"-topmost",
|
||||
True,
|
||||
)
|
||||
|
||||
self.root.attributes(
|
||||
"-alpha",
|
||||
0.99,
|
||||
)
|
||||
|
||||
self.width = self.root.winfo_screenwidth()
|
||||
|
||||
self.height = self.root.winfo_screenheight()
|
||||
|
||||
self.root.geometry(f"{self.width}x{self.height}+0+0")
|
||||
|
||||
self.transparent = "#000001"
|
||||
|
||||
self.root.configure(bg=self.transparent)
|
||||
|
||||
try:
|
||||
self.root.wm_attributes(
|
||||
"-transparentcolor",
|
||||
self.transparent,
|
||||
)
|
||||
|
||||
hwnd = ctypes.windll.user32.GetParent(self.root.winfo_id())
|
||||
|
||||
style = ctypes.windll.user32.GetWindowLongW(
|
||||
hwnd,
|
||||
-20,
|
||||
)
|
||||
|
||||
style |= 0x80000
|
||||
style |= 0x20
|
||||
|
||||
ctypes.windll.user32.SetWindowLongW(
|
||||
hwnd,
|
||||
-20,
|
||||
style,
|
||||
)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.canvas = tk.Canvas(
|
||||
self.root,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
bg=self.transparent,
|
||||
highlightthickness=0,
|
||||
bd=0,
|
||||
)
|
||||
|
||||
self.canvas.pack(
|
||||
fill="both",
|
||||
expand=True,
|
||||
)
|
||||
|
||||
self.color = color
|
||||
self.line_width = line_width
|
||||
self.mode = mode
|
||||
self.visible = True
|
||||
|
||||
self.items = {}
|
||||
self.active_items = []
|
||||
|
||||
self.feedback_color = "#00ff66"
|
||||
|
||||
self.feedback_text = None
|
||||
self.direction_arrow = None
|
||||
|
||||
self.build_modes()
|
||||
|
||||
self.build_feedback()
|
||||
|
||||
self.set_mode(mode)
|
||||
|
||||
def build_feedback(self):
|
||||
self.feedback_text = self.canvas.create_text(
|
||||
self.width // 2,
|
||||
60,
|
||||
text="",
|
||||
fill="#00ff66",
|
||||
font=(
|
||||
"Segoe UI",
|
||||
22,
|
||||
"bold",
|
||||
),
|
||||
state="hidden",
|
||||
)
|
||||
|
||||
self.direction_arrow = self.canvas.create_line(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
fill="#00ff66",
|
||||
width=5,
|
||||
arrow=tk.LAST,
|
||||
state="hidden",
|
||||
)
|
||||
|
||||
def update_feedback(
|
||||
self,
|
||||
result,
|
||||
):
|
||||
state = result["state"]
|
||||
|
||||
if state == "green":
|
||||
color = "#00ff66"
|
||||
|
||||
elif state == "yellow":
|
||||
color = "#ffee00"
|
||||
|
||||
else:
|
||||
color = "#ff3333"
|
||||
|
||||
score = round(result["score"] * 100)
|
||||
|
||||
self.canvas.itemconfigure(
|
||||
self.feedback_text,
|
||||
text=f"{state.upper()} {score}%",
|
||||
fill=color,
|
||||
state="normal",
|
||||
)
|
||||
|
||||
direction = result["direction"]
|
||||
|
||||
self.render_direction_arrow(
|
||||
direction,
|
||||
color,
|
||||
)
|
||||
|
||||
def render_direction_arrow(
|
||||
self,
|
||||
direction,
|
||||
color,
|
||||
):
|
||||
cx = self.width // 2
|
||||
cy = self.height // 2
|
||||
|
||||
if direction == "move_left":
|
||||
coords = (
|
||||
cx + 200,
|
||||
cy,
|
||||
cx - 200,
|
||||
cy,
|
||||
)
|
||||
|
||||
elif direction == "move_right":
|
||||
coords = (
|
||||
cx - 200,
|
||||
cy,
|
||||
cx + 200,
|
||||
cy,
|
||||
)
|
||||
|
||||
elif direction == "reduce_headroom":
|
||||
coords = (
|
||||
cx,
|
||||
cy + 180,
|
||||
cx,
|
||||
cy - 180,
|
||||
)
|
||||
|
||||
elif direction == "recenter_subject":
|
||||
coords = (
|
||||
cx,
|
||||
cy - 180,
|
||||
cx,
|
||||
cy + 180,
|
||||
)
|
||||
|
||||
else:
|
||||
self.canvas.itemconfigure(
|
||||
self.direction_arrow,
|
||||
state="hidden",
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
self.canvas.coords(
|
||||
self.direction_arrow,
|
||||
*coords,
|
||||
)
|
||||
|
||||
self.canvas.itemconfigure(
|
||||
self.direction_arrow,
|
||||
fill=color,
|
||||
state="normal",
|
||||
)
|
||||
|
||||
def schedule(
|
||||
self,
|
||||
callback,
|
||||
ms,
|
||||
):
|
||||
self.root.after(
|
||||
ms,
|
||||
callback,
|
||||
)
|
||||
|
||||
def create_line(
|
||||
self,
|
||||
*coords,
|
||||
):
|
||||
return self.canvas.create_line(
|
||||
*coords,
|
||||
fill=self.color,
|
||||
width=self.line_width,
|
||||
state="hidden",
|
||||
)
|
||||
|
||||
def create_circle(
|
||||
self,
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
fill="",
|
||||
):
|
||||
return self.canvas.create_oval(
|
||||
x - radius,
|
||||
y - radius,
|
||||
x + radius,
|
||||
y + radius,
|
||||
outline=self.color,
|
||||
fill=fill,
|
||||
width=self.line_width,
|
||||
state="hidden",
|
||||
)
|
||||
|
||||
def build_modes(self):
|
||||
w = self.width
|
||||
h = self.height
|
||||
|
||||
cx = w // 2
|
||||
cy = h // 2
|
||||
|
||||
tx = w // 3
|
||||
ttx = (w // 3) * 2
|
||||
|
||||
ty = h // 3
|
||||
tty = (h // 3) * 2
|
||||
|
||||
self.items["thirds"] = [
|
||||
self.create_line(
|
||||
tx,
|
||||
0,
|
||||
tx,
|
||||
h,
|
||||
),
|
||||
self.create_line(
|
||||
ttx,
|
||||
0,
|
||||
ttx,
|
||||
h,
|
||||
),
|
||||
self.create_line(
|
||||
0,
|
||||
ty,
|
||||
w,
|
||||
ty,
|
||||
),
|
||||
self.create_line(
|
||||
0,
|
||||
tty,
|
||||
w,
|
||||
tty,
|
||||
),
|
||||
]
|
||||
|
||||
def hide_all(self):
|
||||
for group in self.items.values():
|
||||
for item in group:
|
||||
self.canvas.itemconfigure(
|
||||
item,
|
||||
state="hidden",
|
||||
)
|
||||
|
||||
def set_mode(
|
||||
self,
|
||||
mode,
|
||||
):
|
||||
if mode not in self.items:
|
||||
mode = "thirds"
|
||||
|
||||
self.mode = mode
|
||||
|
||||
self.hide_all()
|
||||
|
||||
self.active_items = self.items[mode]
|
||||
|
||||
if self.visible:
|
||||
for item in self.active_items:
|
||||
self.canvas.itemconfigure(
|
||||
item,
|
||||
state="normal",
|
||||
)
|
||||
|
||||
def toggle(self):
|
||||
self.visible = not self.visible
|
||||
|
||||
state = "normal" if self.visible else "hidden"
|
||||
|
||||
for item in self.active_items:
|
||||
self.canvas.itemconfigure(
|
||||
item,
|
||||
state=state,
|
||||
)
|
||||
|
||||
def set_color(
|
||||
self,
|
||||
color,
|
||||
):
|
||||
self.color = color
|
||||
|
||||
for group in self.items.values():
|
||||
for item in group:
|
||||
item_type = self.canvas.type(item)
|
||||
|
||||
if item_type == "line":
|
||||
self.canvas.itemconfigure(
|
||||
item,
|
||||
fill=color,
|
||||
)
|
||||
|
||||
elif item_type == "oval":
|
||||
current_fill = self.canvas.itemcget(
|
||||
item,
|
||||
"fill",
|
||||
)
|
||||
|
||||
is_filled = (
|
||||
current_fill
|
||||
and current_fill != ""
|
||||
and current_fill != self.transparent
|
||||
)
|
||||
|
||||
self.canvas.itemconfigure(
|
||||
item,
|
||||
outline=color,
|
||||
fill=(color if is_filled else ""),
|
||||
)
|
||||
|
||||
def resize_overlay(self):
|
||||
width = self.root.winfo_screenwidth()
|
||||
|
||||
height = self.root.winfo_screenheight()
|
||||
|
||||
if width == self.width and height == self.height:
|
||||
return
|
||||
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
self.root.geometry(f"{width}x{height}+0+0")
|
||||
|
||||
self.canvas.config(
|
||||
width=width,
|
||||
height=height,
|
||||
)
|
||||
|
||||
self.canvas.delete("all")
|
||||
|
||||
self.items.clear()
|
||||
|
||||
self.active_items.clear()
|
||||
|
||||
self.build_modes()
|
||||
|
||||
self.build_feedback()
|
||||
|
||||
self.set_mode(self.mode)
|
||||
|
||||
def schedule_monitor_refresh(
|
||||
self,
|
||||
):
|
||||
self.resize_overlay()
|
||||
|
||||
if self.visible:
|
||||
self.schedule(
|
||||
self.schedule_monitor_refresh,
|
||||
1000,
|
||||
)
|
||||
|
||||
def destroy(self):
|
||||
try:
|
||||
self.visible = False
|
||||
|
||||
self.canvas.delete("all")
|
||||
|
||||
self.root.quit()
|
||||
|
||||
self.root.destroy()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
self.root.mainloop()
|
||||
Reference in New Issue
Block a user