From 8797df1c8814e7af1fa2553fe0dcc9d2f6e8a802 Mon Sep 17 00:00:00 2001 From: wangzhizhou <824219521@qq.com> Date: Mon, 9 Nov 2026 11:22:17 +0800 Subject: [PATCH] feat: put the code position numbers in a caption strip under each key Numbers inside the key corner could cover roots when a key carried several positions. Each row now has a 14pt caption strip below it where the numbers sit centred on the key, so no key content is ever obscured and the strip reads as belonging to the row above. Signed-off-by: wangzhizhou <824219521@qq.com> --- ...63\347\255\226\350\256\260\345\275\225.md" | 4 +-- modules/keymap/Sources/KeyboardMapView.swift | 28 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git "a/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" "b/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" index 9578fb82..73b9a0d5 100644 --- "a/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" +++ "b/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" @@ -3143,8 +3143,8 @@ ### ADR-323:键位位次改用图例、简码标注按题型给出 - **决策**: - 1. 位次角标放在**键位右下角**(那里通常是空的),用带底色的胶囊 + 白色圈号 `①②③④`,压在字根上也读得清; - 同一个键出现多次时合并显示(`qqqq` → `①②③④`)。不使用图例行(用户裁定:右下角更省地方、更直观)。 + 1. 位次标注写在**键位下方的序号带**里(每排键下方 14pt 带,居中对齐键位中线),不与键名/字根争位置; + 同一个键出现多次时合并显示(`qqqq` → `①②③④`)。行距相应加大,避免序号被误读成下一排的标注。 2. 答案区下排文字按题型给出:本题目答案(一级 X / 二级 XX / 完整码 XXXX)→ 完整码 → 一级 → 二级, 逐项去重;修掉此前"一律显示 short1 当简码"的问题。 - **理由**:角标压在 50pt 宽的键帽上与键名字根重叠;简码标注错用 short1 会让二级简码题显示一级简码, diff --git a/modules/keymap/Sources/KeyboardMapView.swift b/modules/keymap/Sources/KeyboardMapView.swift index c772cd34..f303b3c8 100644 --- a/modules/keymap/Sources/KeyboardMapView.swift +++ b/modules/keymap/Sources/KeyboardMapView.swift @@ -10,7 +10,10 @@ final class KeyboardMapView: NSView { static let keyHeight: CGFloat = 68 static let keyGap: CGFloat = 6 static let rowGap: CGFloat = 6 - static var totalHeight: CGFloat { keyHeight * 3 + rowGap * 2 } + /// 键位下方的序号带高度:位次写在键外,绝不和键名/字根抢位置。 + static let captionHeight: CGFloat = 14 + static var rowPitch: CGFloat { keyHeight + captionHeight } + static var totalHeight: CGFloat { rowPitch * 3 + rowGap * 2 } /// 字根网格:3 列 × 3 行(每键最多显示 9 个,超出以省略号收尾)。 static let rootColumns = 3 static let rootRows = 3 @@ -65,7 +68,7 @@ final class KeyboardMapView: NSView { // 每排按真实键盘错位:键数少的排整体居中,自然形成阶梯。 let rowWidth = CGFloat(row.count) * keyWidth + CGFloat(row.count - 1) * gap let indent = (bounds.width - rowWidth) / 2 - let y = CGFloat(rowIndex) * (Self.keyHeight + Self.rowGap) + let y = CGFloat(rowIndex) * (Self.rowPitch + Self.rowGap) for (index, letter) in row.enumerated() { let rect = NSRect(x: indent + CGFloat(index) * (keyWidth + gap), y: y, width: keyWidth, height: Self.keyHeight) @@ -101,8 +104,9 @@ final class KeyboardMapView: NSView { in: NSRect(x: rect.minX, y: rect.minY + 4, width: rect.width - 7, height: 19), alignment: .right) drawRoots(entry?.roots ?? [], in: rect, color: rootColor) - drawPositionBadge(for: letter, in: rect, tint: tint, isPressed: isPressed) NSGraphicsContext.restoreGraphicsState() + // 序号画在键位下方的序号带里,必须在裁切之外绘制。 + drawPositionBadge(for: letter, in: rect, tint: tint, isPressed: isPressed) } /// 只显示能稳定渲染成汉字的字根。 @@ -129,22 +133,16 @@ final class KeyboardMapView: NSView { return Array(usable.prefix(capacity - 1)) + ["…"] } - /// 位次角标:画在键位右下角(那里通常是空的),带底色胶囊,压在字根上也读得清。 + /// 位次标注:写在键位**下方**的序号带里(居中),不覆盖键名与字根。 private func drawPositionBadge(for letter: Character, in rect: NSRect, tint: NSColor, isPressed: Bool) { let marks = positionMarks(for: letter) guard !marks.isEmpty, !isPressed else { return } - let attributes: [NSAttributedString.Key: Any] = [ - .font: NSFont.systemFont(ofSize: 9, weight: .bold), - .foregroundColor: NSColor.white] - let string = NSAttributedString(string: marks, attributes: attributes) + let string = NSAttributedString(string: marks, attributes: [ + .font: NSFont.systemFont(ofSize: 9.5, weight: .bold), + .foregroundColor: tint.blended(withFraction: 0.25, of: .labelColor) ?? .labelColor]) let size = string.size() - let inset: CGFloat = 3 - let chip = NSRect(x: rect.maxX - size.width - inset * 2, y: rect.maxY - size.height - inset * 2, - width: size.width + inset * 2, height: size.height + inset * 2) - let path = NSBezierPath(roundedRect: chip, xRadius: chip.height / 2, yRadius: chip.height / 2) - tint.blended(withFraction: 0.25, of: .black)?.withAlphaComponent(0.92).setFill() - path.fill() - string.draw(at: NSPoint(x: chip.minX + inset, y: chip.minY + inset - 1)) + string.draw(at: NSPoint(x: rect.midX - size.width / 2, + y: rect.maxY + (Self.captionHeight - size.height) / 2)) } /// 当前答案里这个键的位次标记(①②③④),同一键多次出现会合并。