From 78b0ca8db7fc3559ee9dc05af0fd2366cc18312e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 16 Oct 2026 23:04:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(explorer):=20=E7=AA=97=E5=8F=A3=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E5=B7=AE=E5=BC=82=E5=8F=AF=E8=A7=81=E5=8C=96=EF=BC=88?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E6=A0=8F/=E8=BE=B9=E6=A1=86=E5=9C=86?= =?UTF-8?q?=E8=A7=92/=E6=8C=89=E9=92=AE=E6=8C=89=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E5=8C=BA=E5=88=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 参考 desktop.vp 的 _draw_app_window 与三枚按钮函数,把 5 种样式的差异做到一眼可辨:标题栏 CLASSIC 蓝紫纯色 / WIN10 近黑 / WIN11 深灰 / WIN7 浅蓝 Aero 渐变(alpha 玻璃) / WINXP 蓝渐变;边框 CLASSIC-win10 直角、WIN7/11/XP 圆角 r=8;按钮 CLASSIC 16x16 深蓝底灰 X、WIN10/11 46x30 无底色灰字形、WIN7 28x20、WINXP 21x21 且红底白 X。新增 _is_in_corner/_is_on_border/_corner_alpha 与按行绘制的 _draw_flat_row/_draw_round_row/_blend_row/_title_row_color;关闭键热区改为与绘制共用同一套几何函数,避免点击错位。标题栏高度仍统一用 TITLE_H=32:app 侧内容区高度依赖 vpui 的 TITLE_H,改高度会让内容错位,故差异只由配色/圆角/按钮体现。 --- Apps/Explorer/desk_server.vp | 404 +++++++++++++++++++++++++++++------ 1 file changed, 333 insertions(+), 71 deletions(-) diff --git a/Apps/Explorer/desk_server.vp b/Apps/Explorer/desk_server.vp index 62211cf..46cada4 100644 --- a/Apps/Explorer/desk_server.vp +++ b/Apps/Explorer/desk_server.vp @@ -21,9 +21,6 @@ _mouse_logged: int = 0 define TITLE_H = 32 # 必须与 vpsdk/vpui.vp 的 TITLE_H 一致(app 用 h - TITLE_H - 2 算内容高) define TITLE_GAP = 2 -define CLOSE_SZ = 14 -define CLOSE_PAD = 5 -define BTN_GAP = 2 define CURSOR_BMP_W = 16 define CURSOR_BMP_H = 16 # 任务栏与窗口装饰尺寸(对齐内核桌面 desktop.vp) @@ -31,6 +28,13 @@ define TASKBAR_H = 50 define TASKBAR_LOGO_SZ = 32 define TASKBAR_ICON_SZ = 36 define TASKBAR_ICON_PAD = 6 +# 窗口按钮尺寸(按样式;poll_input 的关闭键热区必须复用同一套取值) +define BTN_SIZE = 16 # CLASSIC +define BTN_WIN_W = 46 # WIN10/WIN11:宽条,高 = TITLE_H - 2 +define BTN_W7_W = 28 # WIN7 +define BTN_W7_H = 20 +define BTN_XP_SZ = 21 # WINXP +define WIN_RADIUS = 8 # WIN11/WIN7/WINXP 的窗口圆角半径 # 窗口样式(与 vpsdk/window.vp 的 STYLE_* 对齐);当前 CREATE 一律按 CLASSIC 建窗 define STYLE_CLASSIC = 0 define STYLE_WIN10 = 1 @@ -67,6 +71,52 @@ _CURSOR_ARROW: [256]uint8 = [ ] +# 圆角窗口的角点/边框判定(移植自内核桌面 desktop.vp) +def _is_in_corner(px: int, py: int, cx: int, cy: int, r: int) -> int: + dx: int = px - cx + dy: int = py - cy + if dx < 0: dx = 0 - dx + if dy < 0: dy = 0 - dy + if dx <= r and dy <= r: + if dx * dx + dy * dy > r * r: return 0 + return 1 + +def _is_on_border(rx: int, ry: int, ww: int, wh: int, r: int) -> int: + if rx == 0 or rx == ww - 1 or ry == 0 or ry == wh - 1: + return 1 + if ry < r: + if rx < r: + dx: int = rx - r + dy: int = ry - r + if dx * dx + dy * dy >= (r - 1) * (r - 1): return 1 + elif rx >= ww - r: + dx = rx - (ww - r - 1) + dy = ry - r + if dx * dx + dy * dy >= (r - 1) * (r - 1): return 1 + elif ry >= wh - r: + if rx < r: + dx = rx - r + dy = ry - (wh - r - 1) + if dx * dx + dy * dy >= (r - 1) * (r - 1): return 1 + elif rx >= ww - r: + dx = rx - (ww - r - 1) + dy = ry - (wh - r - 1) + if dx * dx + dy * dy >= (r - 1) * (r - 1): return 1 + return 0 + +def _corner_alpha(px: int, py: int, cx: int, cy: int, r: int) -> int: + dx: int = px - cx + dy: int = py - cy + if dx < 0: dx = 0 - dx + if dy < 0: dy = 0 - dy + if dx <= r and dy <= r: + d2: int = dx * dx + dy * dy + if d2 > r * r: return 0 + if d2 >= (r + 1) * (r + 1): return 160 + return 255 + return 255 + + class DeskServer: # 屏幕 fb: uint32* # /dev/fb0 映射后的线性地址 @@ -380,54 +430,261 @@ class DeskServer: px += 1 yy += 1 - # ---------------- 窗口按钮(按行绘字形,CLASSIC 配色)---------------- - def _draw_close_row(self, bx: int, by: int, sz: int, yy: int): - self.row_fill(bx, yy, sz, self.rgb(uint32(40), uint32(40), uint32(70))) - x_col: uint32 = self.rgb(uint32(150), uint32(150), uint32(150)) - cx: int = bx + sz / 2 - cy: int = by + sz / 2 + # ---------------- 窗口逐行绘制(按样式)---------------- + # 把 col 以 alpha 混到后备缓冲已有像素上(WIN7 半透明标题栏用) + def _blend_row(self, x0: int, y: int, w: int, col: uint32, a: int): + if y < 0 or y >= self.fb_h or w <= 0 or a <= 0: return + x: int = x0 + dw: int = w + if x < 0: + dw = dw + x + x = 0 + if x + dw > self.fb_w: + dw = self.fb_w - x + if dw <= 0: return + base: int = y * self.fb_w + i: int = 0 + while i < dw: + idx: int = base + x + i + self.back[idx] = self._blend(self.back[idx], col, a) + i += 1 + + # 标题栏每行颜色:WIN7/WINXP 竖直渐变 + 首两行高光 + 末行暗边,其余样式纯色 + def _title_row_color(self, style: int, rel: int, th: int, active: int, title_col: uint32) -> uint32: + if style != STYLE_WIN7 and style != STYLE_WINXP: + return title_col + ratio: int = (rel * 100) / th + if ratio > 100: ratio = 100 + r: int = 0 + g: int = 0 + b: int = 0 + if style == STYLE_WIN7: + if active != 0: + r = 156 + ((186 - 156) * ratio) / 100 + g = 181 + ((209 - 181) * ratio) / 100 + b = 209 + ((233 - 209) * ratio) / 100 + else: + r = 180 + ((200 - 180) * ratio) / 100 + g = 195 + ((210 - 195) * ratio) / 100 + b = 210 + ((225 - 210) * ratio) / 100 + else: + if active != 0: + r = 107 + ((58 - 107) * ratio) / 100 + g = 158 + ((124 - 158) * ratio) / 100 + b = 212 + ((195 - 212) * ratio) / 100 + else: + r = 150 + ((115 - 150) * ratio) / 100 + g = 170 + ((135 - 170) * ratio) / 100 + b = 205 + ((175 - 205) * ratio) / 100 + col: uint32 = self.rgb(uint32(r), uint32(g), uint32(b)) + if rel == 0: + if style == STYLE_WIN7: + col = self._blend(col, self.rgb(uint32(220), uint32(235), uint32(255)), 50) + else: + col = self._blend(col, self.rgb(uint32(200), uint32(225), uint32(255)), 50) + elif rel == 1: + if style == STYLE_WIN7: + col = self._blend(col, self.rgb(uint32(210), uint32(225), uint32(250)), 20) + else: + col = self._blend(col, self.rgb(uint32(200), uint32(225), uint32(255)), 25) + if rel == th - 1: + if style == STYLE_WIN7: + col = self._blend(col, self.rgb(uint32(130), uint32(160), uint32(200)), 25) + else: + col = self._blend(col, self.rgb(uint32(100), uint32(160), uint32(230)), 40) + return col + + # 直边行:整行底色 + 内容 blit + 左右/上下 1px 边框 + def _draw_flat_row(self, s: desk.WinSlot*, yy: int, rel: int, row_col: uint32, + row_is_title: int, border_col: uint32, title_alpha: int, + buf: uint32*, fw: int, fh: int, content_y0: int): + wx: int = s.ux + ww: int = s.w + wh: int = s.h + content_row: int = yy - content_y0 + if row_is_title != 0 and title_alpha < 255: + self._blend_row(wx + 1, yy, ww - 2, row_col, title_alpha) + else: + self.row_fill(wx, yy, ww, row_col) + if rel >= TITLE_H + TITLE_GAP and rel < wh - 1 and content_row >= 0 and content_row < fh: + self.row_blit(wx + 1, yy, buf, content_row * fw + 1, ww - 2) + if rel == 0 or rel == wh - 1: + self.row_fill(wx, yy, ww, border_col) + else: + self.row_fill(wx, yy, 1, border_col) + self.row_fill(wx + ww - 1, yy, 1, border_col) + + # 圆角带的行:逐像素按圆角形状裁剪,画边框/标题渐变/内容 + def _draw_round_row(self, s: desk.WinSlot*, yy: int, rel: int, row_col: uint32, + row_is_title: int, outline_col: uint32, r: int, title_alpha: int, + buf: uint32*, fw: int, fh: int, content_y0: int): + wx: int = s.ux + ww: int = s.w + wh: int = s.h + content_row: int = yy - content_y0 + do_blit: int = 0 + if rel >= TITLE_H + TITLE_GAP and rel < wh - 1 and content_row >= 0 and content_row < fh: + do_blit = 1 + px: int = wx + xend: int = wx + ww + while px < xend: + if px >= 0 and px < self.fb_w: + rx: int = px - wx + in_corner: int = 1 + on_border: int = 0 + if rel < r: + if rx < r: + in_corner = _is_in_corner(rx, rel, r, r, r) + elif rx >= ww - r: + in_corner = _is_in_corner(rx, rel, ww - r - 1, r, r) + elif rel >= wh - r: + if rx < r: + in_corner = _is_in_corner(rx, rel, r, wh - r - 1, r) + elif rx >= ww - r: + in_corner = _is_in_corner(rx, rel, ww - r - 1, wh - r - 1, r) + if in_corner == 0: + on_border = _is_on_border(rx, rel, ww, wh, r) + if on_border == 0: + px += 1 + continue + is_border_pixel: int = 0 + if on_border != 0 or _is_on_border(rx, rel, ww, wh, r) != 0: + is_border_pixel = 1 + idx: int = yy * self.fb_w + px + if is_border_pixel == 0 and do_blit != 0: + self.back[idx] = buf[content_row * fw + rx] + px += 1 + continue + col: uint32 = row_col + if is_border_pixel != 0: + col = outline_col + ca: int = 255 + if rel < r: + if rx < r: + ca = _corner_alpha(rx, rel, r, r, r) + elif rx >= ww - r: + ca = _corner_alpha(rx, rel, ww - r - 1, r, r) + elif rel >= wh - r: + if rx < r: + ca = _corner_alpha(rx, rel, r, wh - r - 1, r) + elif rx >= ww - r: + ca = _corner_alpha(rx, rel, ww - r - 1, wh - r - 1, r) + if is_border_pixel != 0 and ca > 0 and ca < 255: + ca = 255 + if row_is_title != 0 and title_alpha < 255 and rel >= 1 and rx >= 1 and rx < ww - 1 and ca == 255 and is_border_pixel == 0: + ca = title_alpha + if ca <= 0: + px += 1 + continue + if ca < 255: + self.back[idx] = self._blend(self.back[idx], col, ca) + else: + self.back[idx] = col + px += 1 + + # ---------------- 窗口按钮(按样式逐行绘制)---------------- + # 关闭键底色圆角(WIN7/WINXP 的红色圆角块) + def _round_fill_row(self, bx: int, by: int, bw: int, bh: int, yy: int, col: uint32, r: int): + lry: int = yy - by + if lry < 0 or lry >= bh: return + lx: int = 0 + while lx < bw: + keep: int = 1 + if lry < r: + if lx < r: + keep = _is_in_corner(lx, lry, r, r, r) + elif lx >= bw - r: + keep = _is_in_corner(lx, lry, bw - r - 1, r, r) + elif lry >= bh - r: + if lx < r: + keep = _is_in_corner(lx, lry, r, bh - r - 1, r) + elif lx >= bw - r: + keep = _is_in_corner(lx, lry, bw - r - 1, bh - r - 1, r) + if keep != 0: + self.row_fill(bx + lx, yy, 1, col) + lx += 1 + + def _draw_close_row(self, bx: int, by: int, bw: int, bh: int, yy: int, style: int): + lry: int = yy - by + if lry < 0 or lry >= bh: return + cx: int = bx + bw / 2 + cy: int = by + bh / 2 + d: int = 3 + if bw >= 30: d = 4 + x_col: uint32 = self.rgb(uint32(200), uint32(200), uint32(200)) + if style == STYLE_CLASSIC: + self.row_fill(bx, yy, bw, self.rgb(uint32(40), uint32(40), uint32(70))) + elif style == STYLE_WIN7 or style == STYLE_WINXP: + self._round_fill_row(bx, by, bw, bh, yy, self.rgb(uint32(200), uint32(50), uint32(50)), 3) + x_col = self.rgb(uint32(255), uint32(255), uint32(255)) + else: + x_col = self.rgb(uint32(150), uint32(150), uint32(150)) i: int = yy - cy - if i >= 0 - 3 and i <= 3: + if i >= 0 - d and i <= d: self.row_fill(cx + i, yy, 1, x_col) self.row_fill(cx - i, yy, 1, x_col) - def _draw_min_row(self, bx: int, by: int, sz: int, yy: int): - cx: int = bx + sz / 2 - cy: int = by + sz / 2 + def _draw_min_row(self, bx: int, by: int, bw: int, bh: int, yy: int, style: int): + cx: int = bx + bw / 2 + cy: int = by + bh / 2 + lw: int = 5 + if bw >= 30: lw = 8 if yy == cy + 3: - self.row_fill(cx - 5, yy, 11, self.rgb(uint32(180), uint32(180), uint32(180))) + self.row_fill(cx - lw, yy, lw * 2 + 1, self.rgb(uint32(180), uint32(180), uint32(180))) - def _draw_max_row(self, bx: int, by: int, sz: int, yy: int): - col: uint32 = self.rgb(uint32(180), uint32(180), uint32(180)) - cx: int = bx + sz / 2 - cy: int = by + sz / 2 - q: int = 4 + def _draw_max_row(self, bx: int, by: int, bw: int, bh: int, yy: int, style: int): + cx: int = bx + bw / 2 + cy: int = by + bh / 2 + sz: int = 4 + if bw >= 30: sz = 6 dy: int = yy - cy - if dy < 0: dy = 0 - dy - if dy > q: return - if dy == q or yy == cy - q + 1: - self.row_fill(cx - q, yy, 2 * q + 1, col) + if dy < 0 - sz or dy > sz: return + col: uint32 = self.rgb(uint32(180), uint32(180), uint32(180)) + if dy == 0 - sz or dy == 0 - sz + 1 or dy == sz: + self.row_fill(cx - sz, yy, sz * 2 + 1, col) else: - self.row_fill(cx - q, yy, 1, col) - self.row_fill(cx + q, yy, 1, col) + self.row_fill(cx - sz, yy, 1, col) + self.row_fill(cx + sz, yy, 1, col) + + # 关闭键宽/高/右内边距(按样式;poll_input 热区复用这三者) + def _close_btn_w(self, style: int) -> int: + if style == STYLE_WIN10 or style == STYLE_WIN11: return BTN_WIN_W + if style == STYLE_WIN7: return BTN_W7_W + if style == STYLE_WINXP: return BTN_XP_SZ + return BTN_SIZE + + def _close_btn_h(self, style: int) -> int: + if style == STYLE_WIN10 or style == STYLE_WIN11: return TITLE_H - 2 + if style == STYLE_WIN7: return BTN_W7_H + if style == STYLE_WINXP: return BTN_XP_SZ + return BTN_SIZE + + def _close_btn_pad(self, style: int) -> int: + if style == STYLE_WIN10 or style == STYLE_WIN11: return 0 + if style == STYLE_WIN7 or style == STYLE_WINXP: return 5 + return 4 def _draw_window_btns(self, s: desk.WinSlot*, y0: int, y1: int, th: int): wx: int = s.ux wy: int = s.uy ww: int = s.w - sz: int = CLOSE_SZ - by: int = wy + (th - sz) / 2 - close_x: int = wx + ww - sz - CLOSE_PAD - max_x: int = close_x - sz - BTN_GAP - min_x: int = max_x - sz - BTN_GAP + style: int = s.style + bw: int = self._close_btn_w(style) + bh: int = self._close_btn_h(style) + by: int = wy + (th - bh) / 2 + close_x: int = wx + ww - bw - self._close_btn_pad(style) + gap: int = 0 + if style == STYLE_WIN7 or style == STYLE_WINXP: gap = 1 + max_x: int = close_x - bw - gap + min_x: int = max_x - bw - gap yy: int = y0 if yy < by: yy = by yend: int = y1 - if yend > by + sz: yend = by + sz + if yend > by + bh: yend = by + bh while yy < yend: - self._draw_close_row(close_x, by, sz, yy) - self._draw_min_row(min_x, by, sz, yy) - self._draw_max_row(max_x, by, sz, yy) + self._draw_close_row(close_x, by, bw, bh, yy, style) + self._draw_min_row(min_x, by, bw, bh, yy, style) + self._draw_max_row(max_x, by, bw, bh, yy, style) yy += 1 # ---------------- 任务栏 ---------------- @@ -540,61 +797,70 @@ class DeskServer: s: desk.WinSlot* = self.slot(win) wx: int = s.ux wy: int = s.uy - ww: int = s.w wh: int = s.h th: int = TITLE_H style: int = s.style active: int = 0 if s.z_order == self._top_z(): active = 1 - # 样式配色:CLASSIC 为默认;其余样式仅配色/分隔线可区分(几何同 CLASSIC) + # 每样式调色板(对齐内核桌面 desktop.vp 的 _draw_app_window) title_col: uint32 = self.rgb(uint32(50), uint32(50), uint32(90)) border_col: uint32 = self.rgb(uint32(100), uint32(100), uint32(180)) + outline_col: uint32 = self.rgb(uint32(100), uint32(100), uint32(180)) content_col: uint32 = self.rgb(uint32(30), uint32(30), uint32(50)) has_separator: int = 1 + rounded: int = 0 + title_alpha: int = 255 if style == STYLE_WIN10: has_separator = 0 if active != 0: title_col = self.rgb(uint32(0), uint32(0), uint32(0)) - border_col = self.rgb(uint32(0), uint32(0), uint32(0)) content_col = self.rgb(uint32(32), uint32(32), uint32(32)) + outline_col = self.rgb(uint32(80), uint32(80), uint32(80)) else: title_col = self.rgb(uint32(32), uint32(32), uint32(32)) - border_col = self.rgb(uint32(32), uint32(32), uint32(32)) content_col = self.rgb(uint32(24), uint32(24), uint32(24)) + outline_col = self.rgb(uint32(60), uint32(60), uint32(60)) + border_col = title_col elif style == STYLE_WIN11: has_separator = 0 + rounded = 1 if active != 0: title_col = self.rgb(uint32(32), uint32(32), uint32(32)) - border_col = self.rgb(uint32(32), uint32(32), uint32(32)) content_col = self.rgb(uint32(32), uint32(32), uint32(32)) + outline_col = self.rgb(uint32(70), uint32(70), uint32(70)) else: title_col = self.rgb(uint32(40), uint32(40), uint32(40)) - border_col = self.rgb(uint32(40), uint32(40), uint32(40)) content_col = self.rgb(uint32(40), uint32(40), uint32(40)) + outline_col = self.rgb(uint32(60), uint32(60), uint32(60)) + border_col = title_col elif style == STYLE_WIN7: has_separator = 0 + rounded = 1 + title_alpha = 102 + content_col = self.rgb(uint32(240), uint32(240), uint32(240)) if active != 0: title_col = self.rgb(uint32(156), uint32(181), uint32(209)) - border_col = self.rgb(uint32(156), uint32(181), uint32(209)) - content_col = self.rgb(uint32(240), uint32(240), uint32(240)) + outline_col = self.rgb(uint32(100), uint32(130), uint32(170)) else: title_col = self.rgb(uint32(180), uint32(195), uint32(210)) - border_col = self.rgb(uint32(180), uint32(195), uint32(210)) - content_col = self.rgb(uint32(240), uint32(240), uint32(240)) + outline_col = self.rgb(uint32(140), uint32(155), uint32(175)) + border_col = title_col elif style == STYLE_WINXP: has_separator = 0 + rounded = 1 + content_col = self.rgb(uint32(235), uint32(235), uint32(235)) if active != 0: title_col = self.rgb(uint32(107), uint32(158), uint32(212)) - border_col = self.rgb(uint32(107), uint32(158), uint32(212)) - content_col = self.rgb(uint32(235), uint32(235), uint32(235)) + outline_col = self.rgb(uint32(43), uint32(87), uint32(151)) else: title_col = self.rgb(uint32(140), uint32(160), uint32(195)) - border_col = self.rgb(uint32(140), uint32(160), uint32(195)) - content_col = self.rgb(uint32(235), uint32(235), uint32(235)) + outline_col = self.rgb(uint32(100), uint32(115), uint32(145)) + border_col = title_col else: if active != 0: title_col = self.rgb(uint32(70), uint32(70), uint32(130)) border_col = self.rgb(uint32(130), uint32(130), uint32(220)) + outline_col = border_col # 阴影画在窗口本体之前(混到已合成的下层像素上),其行范围可能超出窗口外框 if SHADOW_ENABLED != 0: @@ -605,33 +871,26 @@ class DeskServer: fw: int = int(s.fb_w) fh: int = int(s.fb_h) content_y0: int = wy + th + TITLE_GAP + r: int = WIN_RADIUS yy: int = y0 if yy < wy: yy = wy yend: int = y1 if yend > wy + wh: yend = wy + wh while yy < yend: rel: int = yy - wy - if rel == 0: - self.row_fill(wx, yy, ww, border_col) # 上边框 - elif rel < th: - self.row_fill(wx, yy, ww, title_col) # 标题栏 - elif rel == th: - if has_separator != 0: - self.row_fill(wx, yy, ww, border_col) # 标题/内容分隔线 - else: - self.row_fill(wx, yy, ww, content_col) - elif rel == th + 1: - self.row_fill(wx, yy, ww, content_col) - elif rel == wh - 1: - self.row_fill(wx, yy, ww, border_col) # 下边框 + row_is_title: int = 0 + row_col: uint32 = content_col + if rel < th: + row_is_title = 1 + row_col = self._title_row_color(style, rel, th, active, title_col) + elif rel == th and has_separator != 0: + row_col = border_col # 标题/内容分隔线(CLASSIC) + if rounded != 0 and (rel < r or rel >= wh - r): + self._draw_round_row(s, yy, rel, row_col, row_is_title, outline_col, r, + title_alpha, buf, fw, fh, content_y0) else: - self.row_fill(wx, yy, ww, content_col) - row: int = yy - content_y0 - if row >= 0 and row < fh: - self.row_blit(wx + 1, yy, buf, row * fw + 1, ww - 2) - if rel > 0 and rel < wh - 1: - self.row_fill(wx, yy, 1, border_col) # 左边框 - self.row_fill(wx + ww - 1, yy, 1, border_col) # 右边框 + self._draw_flat_row(s, yy, rel, row_col, row_is_title, border_col, + title_alpha, buf, fw, fh, content_y0) yy += 1 self._draw_window_btns(s, y0, y1, th) @@ -866,10 +1125,13 @@ class DeskServer: hit: int = self.hit_test(self.cx, self.cy) if hit >= 0: s: desk.WinSlot* = self.slot(hit) - bx: int = s.ux + s.w - CLOSE_SZ - CLOSE_PAD - by: int = s.uy + (TITLE_H - CLOSE_SZ) / 2 + # 关闭键热区按样式尺寸算,必须与 _draw_window_btns 一致 + cw: int = self._close_btn_w(s.style) + ch: int = self._close_btn_h(s.style) + bx: int = s.ux + s.w - cw - self._close_btn_pad(s.style) + by: int = s.uy + (TITLE_H - ch) / 2 in_close: int = 0 - if self.cx >= bx and self.cx < bx + CLOSE_SZ and self.cy >= by and self.cy < by + CLOSE_SZ: + if self.cx >= bx and self.cx < bx + cw and self.cy >= by and self.cy < by + ch: in_close = 1 self.focus(hit) if in_close != 0: