Add helper.py

This commit is contained in:
admin
2026-05-25 23:40:39 +00:00
parent 4cb502eb7e
commit 45aa457640

423
helper.py Normal file
View 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()