# -*- coding: utf-8 -*- r'''验「弹窗位置/大小可配置」和「屏幕提示条默认关」。 == 用户的要求 == 1. 弹文字窗口:位置和大小都能自定义(原来写死右下角) 2. 屏幕共享提示条:以后不要弹,像 UU 远程一样啥窗口都没有 == 验什么 == 一、设置项都在,而且默认值符合要求 (位置默认右下角 = 不改变老用户习惯; 但 show_screen_notice 默认必须是 False) 二、_notice_geometry 对 6 种位置算出来的坐标对不对 三、三处写死的 geometry 都改成了调 helper(不能再有硬编码的右下角) 四、字号和宽度是可配置的 五、屏幕提示条真的会读那个开关 == 为什么第三层重要 == 这次改了 3 处 geometry、5 处字号、2 处宽度。 如果漏掉一处,表现就是"有一个窗口还在右下角" —— 而用户只会看到"你改了没用"。所以必须断言**没有残留的硬编码**。 ''' from __future__ import annotations import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "windows")) FAILS: list = [] def check(name: str, ok: bool, why: str = "") -> None: print(" [%s] %s%s" % ("PASS" if ok else "FAIL", name, (" —— " + why) if why else "")) if not ok: FAILS.append(name) HEADLESS = ROOT / "windows" / "lanremote" / "headless.py" CONFIG = ROOT / "windows" / "lanremote" / "config.py" def main() -> int: print("=" * 58) print(" 弹窗位置/大小可配置 + 屏幕提示条默认关") print("=" * 58) print() src = HEADLESS.read_text(encoding="utf-8") cfg_src = CONFIG.read_text(encoding="utf-8") # ---------------- 一、设置项 ---------------- print("一、设置项") from lanremote.config import DEFAULT_SETTINGS as D for key in ("notice_position", "notice_x", "notice_y", "notice_width", "notice_font_size", "show_screen_notice"): check(" %s 存在" % key, key in D) check("位置默认右下角(不改变老用户习惯)", D.get("notice_position") == "bottom-right", "拿到 %r" % D.get("notice_position")) check("**屏幕提示条默认关**(用户明确要求)", D.get("show_screen_notice") is False, "拿到 %r —— 这个默认必须是 False" % D.get("show_screen_notice")) check("字号默认 11(原来的值)", D.get("notice_font_size") == 11) check("宽度默认 0(自适应)", D.get("notice_width") == 0) # ---------------- 二、_notice_geometry 算得对不对 ---------------- print() print("二、_notice_geometry 的坐标计算") # 直接复刻逻辑来验(不启动 Tk)—— 和源码里的算法必须一致 def geom(pos, w, h, screen=(1920, 1080), cx=0, cy=0): screen_w, screen_h = screen pad, pad_bottom = 24, 72 if pos == "custom": x = max(0, min(max(0, screen_w - w), cx)) y = max(0, min(max(0, screen_h - h), cy)) return (x, y) if pos == "center": return (max(0, (screen_w - w) // 2), max(0, (screen_h - h) // 2)) left = pos in ("top-left", "bottom-left") top = pos in ("top-left", "top-right") x = pad if left else screen_w - w - pad y = pad if top else screen_h - h - pad_bottom return (max(0, x), max(0, y)) cases = [ ("bottom-right", (1920 - 300 - 24, 1080 - 100 - 72), "右下角"), ("bottom-left", (24, 1080 - 100 - 72), "左下角"), ("top-right", (1920 - 300 - 24, 24), "右上角"), ("top-left", (24, 24), "左上角"), ("center", ((1920 - 300) // 2, (1080 - 100) // 2), "屏幕正中间"), ] for pos, want, label in cases: got = geom(pos, 300, 100) check(" %s(%s)" % (pos, label), got == want, "期望 %s,拿到 %s" % (want, got)) # custom:正常值 check(" custom 用指定坐标", geom("custom", 300, 100, cx=500, cy=400) == (500, 400)) # custom:超范围要夹回来 check(" custom 超右边界被夹住", geom("custom", 300, 100, cx=99999, cy=0) == (1920 - 300, 0), "拿到 %s" % (geom("custom", 300, 100, cx=99999, cy=0),)) check(" custom 负坐标被夹到 0", geom("custom", 300, 100, cx=-50, cy=-50) == (0, 0)) # ---------------- 三、没有残留的硬编码定位 ---------------- print() print("三、源码里不能有残留的硬编码(漏一处用户就看得见)") check("没有写死的右下角 geometry", "screen_h - height - 72" not in src, "还有窗口固定放右下角") check("没有写死的字号 11", '"Microsoft YaHei UI", 11, "bold"' not in src, "还有窗口用写死的字号") # ⚠ 这里要排除 helper 自己那处 —— _notice_width 里 # uto = max(240, win.winfo_reqwidth()) 是**自适应的兜底值**, # 属于故意保留的。第一版断言太粗,把这处也算成写死了。 hard = [ln for ln in src.splitlines() if "max(240, win.winfo_reqwidth())" in ln and "auto =" not in ln] check("没有别处写死的宽度 240", not hard, "还有窗口用写死的宽度:%s" % hard) n_geom = src.count("self._notice_geometry(width, height)") check("三处定位都改调 helper(实际 %d 处)" % n_geom, n_geom == 3, "应该是 3 处(通知×2 + 屏幕提示×1)") check("有 _notice_geometry 方法", "def _notice_geometry(self" in src) check("有 _notice_font 方法", "def _notice_font(self" in src) check("有 _notice_width 方法", "def _notice_width(self" in src) # ---------------- 四、屏幕提示条读开关 ---------------- print() print("四、屏幕提示条") m = re.search(r"def set_screen_sharing\(self.*?(?=\n def )", src, re.S) body = m.group(0) if m else "" check("找到了 set_screen_sharing", bool(body)) check("它读了 show_screen_notice", 'store.get("show_screen_notice")' in body, "没读开关的话提示条还是会强制弹出来") # 读开关的判断必须在 _show_notice 之前 i_check = body.find('store.get("show_screen_notice")') i_show = body.find("_show_notice(") check("判断在弹窗之前(关着就不会弹)", 0 <= i_check < i_show, "顺序反了的话会先弹再判断") # ---------------- 五、设置界面里能不能改 ---------------- print() print("五、设置界面") ui_src = (ROOT / "windows" / "lanremote" / "ui.py").read_text( encoding="utf-8") has_any = any(k in ui_src for k in ("notice_position", "notice_width", "notice_font_size", "show_screen_notice")) check("设置界面里有这些项", has_any, "配置项加了但界面没入口的话,用户根本改不了") print() print("=" * 58) if FAILS: print(" 失败 %d 项:%s" % (len(FAILS), ", ".join(FAILS))) return 1 print(" 全部通过") return 0 if __name__ == "__main__": sys.exit(main())