mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-09-06 03:20:49 +02:00
feat: initialize CCMA member administration
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import tkinter as tk
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class MonitorBounds:
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
primary: bool = False
|
||||
|
||||
@property
|
||||
def center(self) -> tuple[int, int]:
|
||||
return self.x + self.width // 2, self.y + self.height // 2
|
||||
|
||||
def as_tuple(self) -> tuple[int, int, int, int]:
|
||||
return self.x, self.y, self.width, self.height
|
||||
|
||||
|
||||
def available_monitors(root: tk.Misc | None = None) -> list[MonitorBounds]:
|
||||
try:
|
||||
from screeninfo import get_monitors
|
||||
|
||||
monitors = [
|
||||
MonitorBounds(
|
||||
int(monitor.x),
|
||||
int(monitor.y),
|
||||
int(monitor.width),
|
||||
int(monitor.height),
|
||||
bool(getattr(monitor, "is_primary", False)),
|
||||
)
|
||||
for monitor in get_monitors()
|
||||
]
|
||||
if monitors:
|
||||
return monitors
|
||||
except Exception:
|
||||
pass
|
||||
if root is None:
|
||||
return []
|
||||
return [
|
||||
MonitorBounds(
|
||||
int(root.winfo_vrootx()),
|
||||
int(root.winfo_vrooty()),
|
||||
int(root.winfo_vrootwidth()),
|
||||
int(root.winfo_vrootheight()),
|
||||
True,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def preferred_monitor(
|
||||
root: tk.Misc,
|
||||
saved_bounds: tuple[int, int, int, int] | None = None,
|
||||
) -> MonitorBounds:
|
||||
monitors = available_monitors(root)
|
||||
if saved_bounds:
|
||||
for monitor in monitors:
|
||||
if monitor.as_tuple() == saved_bounds:
|
||||
return monitor
|
||||
return next((monitor for monitor in monitors if monitor.primary), monitors[0])
|
||||
|
||||
|
||||
def monitor_for_geometry(root: tk.Misc, geometry: str) -> MonitorBounds:
|
||||
monitors = available_monitors(root)
|
||||
parsed = parse_geometry(geometry)
|
||||
if not parsed:
|
||||
return next((monitor for monitor in monitors if monitor.primary), monitors[0])
|
||||
width, height, x, y = parsed
|
||||
center_x, center_y = x + width // 2, y + height // 2
|
||||
containing = [
|
||||
monitor
|
||||
for monitor in monitors
|
||||
if monitor.x <= center_x < monitor.x + monitor.width
|
||||
and monitor.y <= center_y < monitor.y + monitor.height
|
||||
]
|
||||
if containing:
|
||||
return containing[0]
|
||||
return min(monitors, key=lambda monitor: _distance_squared(monitor.center, (center_x, center_y)))
|
||||
|
||||
|
||||
def centered_geometry(width: int, height: int, monitor: MonitorBounds) -> str:
|
||||
fitted_width = min(width, max(640, monitor.width - 80))
|
||||
fitted_height = min(height, max(480, monitor.height - 80))
|
||||
x = monitor.x + (monitor.width - fitted_width) // 2
|
||||
y = monitor.y + (monitor.height - fitted_height) // 2
|
||||
return format_geometry(fitted_width, fitted_height, x, y)
|
||||
|
||||
|
||||
def ensure_visible_geometry(geometry: str, monitor: MonitorBounds) -> str:
|
||||
parsed = parse_geometry(geometry)
|
||||
if not parsed:
|
||||
return centered_geometry(1500, 860, monitor)
|
||||
width, height, x, y = parsed
|
||||
width = min(width, max(640, monitor.width - 40))
|
||||
height = min(height, max(480, monitor.height - 40))
|
||||
x = min(max(x, monitor.x), monitor.x + monitor.width - width)
|
||||
y = min(max(y, monitor.y), monitor.y + monitor.height - height)
|
||||
return format_geometry(width, height, x, y)
|
||||
|
||||
|
||||
def parse_geometry(geometry: str) -> tuple[int, int, int, int] | None:
|
||||
match = re.fullmatch(r"(\d+)x(\d+)([+-]\d+)([+-]\d+)", geometry.strip())
|
||||
if not match:
|
||||
return None
|
||||
return tuple(int(value) for value in match.groups()) # type: ignore[return-value]
|
||||
|
||||
|
||||
def format_geometry(width: int, height: int, x: int, y: int) -> str:
|
||||
return f"{width}x{height}{x:+d}{y:+d}"
|
||||
|
||||
|
||||
def _distance_squared(left: tuple[int, int], right: tuple[int, int]) -> int:
|
||||
return (left[0] - right[0]) ** 2 + (left[1] - right[1]) ** 2
|
||||
Reference in New Issue
Block a user