# text_metrics —— §8.8 seam ⑦ / ⑩ 收口:头顶子标签 / 掉落名条排版的文本尺寸 # 从「字符数 * 约 7px」/「单行 15px」估算换成 CGraphicTextInstance::GetTextSize 的 # 真实字体度量 1:1(增量 123 换宽 w、增量 124 换高 h、增量 125 加 owner 子串独立度量)。 # ArrangeTextTail(PythonTextTail.cpp:211-320 角色块、:160-190 item 块)里 # iNameWidth / iTitleWidth / iLevelWidth / guildW,以及 item 尾标框的 xSize / ySize # (框 yEnd = ySize,:749 / :809),参考端全部来自 `pTextInstance->GetTextSize(&w, &h)`。 # Godot 的 Font.get_string_size() 是 1:1 对应物——本模块把它包成纯静态查询,并在无字体 # (headless / 未配主题)时回退到旧的字符数估宽 / 单行估高,保持 name_tail_layout / # text_tail_arrange 的接口不变。 # (与 name_color.gd / text_tail.gd / chat_tail.gd / name_show.gd / damage_effect.gd / # target_board.gd / pick_show.gd / name_tail_layout.gd / text_tail_arrange.gd 同一套 # 纯静态镜像套路,本模块是第 30 个 canonical。) # # REF(40250 ClientVS22 source/ 为唯一基线): # UserInterface/PythonTextTail.cpp:225 pGuildNameInstance->GetTextSize(&iWidth, &iHeight) # UserInterface/PythonTextTail.cpp:233 pTextTail->pTextInstance->GetTextSize(&iNameWidth, &iNameHeight) # UserInterface/PythonTextTail.cpp:240 pTitle->GetTextSize(&iTitleWidth, &iTitleHeight) # UserInterface/PythonTextTail.cpp:267 pLevel->GetTextSize(&iLevelWidth, &iLevelHeight)(有称号分支) # UserInterface/PythonTextTail.cpp:297 pLevel->GetTextSize(&iLevelWidth, &iLevelHeight)(只有等级分支) # UserInterface/PythonTextTail.cpp:733 pOwnerTextInstance->GetTextSize(&xOwnerSize, &yOwnerSize) # UserInterface/PythonTextTail.cpp:748 pTextInstance->GetTextSize(&xSize, &ySize)(SetTextTailOwnerText) # UserInterface/PythonTextTail.cpp:809 pTextInstance->GetTextSize(&xSize, &ySize)(SetTextTailText,item 框尺寸) # —— GetTextSize 由 CGraphicTextInstance 转发到字体的实际字形排版度量(含字距、非等宽), # 不是「字符数 * 定宽」。poc 之前的 SUBTAG_CHAR_W_PX / TAG_CHAR_W_PX(7.0) 是它 w 的近似、 # TAG_LINE_H_PX(15.0) 是它 h 的近似。 # # seam ⑦ / ⑩:本模块只负责「量文本宽 / 高」。有字体时 = get_string_size 的精确像素(1:1); # 无字体时回退字符数估宽 / 单行估高(headless 测试、或工程未配 Label3D.font 且无 # ThemeDB.fallback_font 的极端情况)。折算成世界坐标仍由调用方按各 Label3D 的 pixel_size # 处理(见 name_tail_layout.subtag_world_x / text_tail_arrange)。子标签竖排 vs 参考同一 # 屏幕行、无公会徽记 mark 实体这两条 seam ⑦ 遗留不在本模块范围。 extends RefCounted # 无字体 / font_size 非法时的每字符估宽(=增量 121 之前 net_world.SUBTAG_CHAR_W_PX、 # ground_items.TAG_CHAR_W_PX 用的 7.0)。仅作兜底,有字体时不参与。 const FALLBACK_CHAR_W_PX := 7.0 # 无字体 / font_size 非法时的单行估高(=增量 124 之前 ground_items.TAG_LINE_H_PX 用的 # 15.0)。仅作兜底,有字体时走 get_string_size(...).y。 const FALLBACK_LINE_H_PX := 15.0 # GetTextSize(&w, &h) 1:1:text 在 font @ font_size 下的像素尺寸。 # 空串 / font 为 null / font_size <= 0 -> Vector2.ZERO(对齐参考端未建 text instance # 时该子标签不参与 ArrangeTextTail 的宽度计算)。 static func text_size(font: Font, text: String, font_size: int) -> Vector2: if text == "" or font == null or font_size <= 0: return Vector2.ZERO return font.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size) # ArrangeTextTail 里各 iXxxWidth 取的就是 GetTextSize 的 w。 # 有字体且量得正宽 -> 精确像素;否则(无字体 / 非法 size)-> 字符数 * fallback_char_px。 # 空串恒 0(参考端无 text instance -> 该项不占宽)。 static func width_of(font: Font, text: String, font_size: int, fallback_char_px := FALLBACK_CHAR_W_PX) -> float: if text == "": return 0.0 var w := text_size(font, text, font_size).x if w > 0.0: return w return float(text.length()) * fallback_char_px # Label3D 便捷入口:从节点自身取字体(Label3D.font 未设时回落 ThemeDB.fallback_font) # 和 font_size,量出该 Label3D 当前文本的像素宽。label 为 null -> 0。 static func label_width(label: Label3D, fallback_char_px := FALLBACK_CHAR_W_PX) -> float: if label == null: return 0.0 var f: Font = label.font if f == null: f = ThemeDB.fallback_font return width_of(f, label.text, label.font_size, fallback_char_px) # GetTextSize 的 h:item 尾标框 yEnd = ySize(PythonTextTail.cpp:749 / :809)。单行文本的 # ySize ≈ 字体行高(ascent + descent),与具体字形无关。空串恒 0(参考端无 text # instance -> 不占高);有字体量得正高 -> 精确像素;否则(无字体 / 非法 size)-> fallback。 static func height_of(font: Font, text: String, font_size: int, fallback_line_px := FALLBACK_LINE_H_PX) -> float: if text == "": return 0.0 var h := text_size(font, text, font_size).y if h > 0.0: return h return fallback_line_px # Label3D 便捷入口:同 label_width,量该 Label3D 当前文本的像素高。label 为 null -> 0。 static func label_height(label: Label3D, fallback_line_px := FALLBACK_LINE_H_PX) -> float: if label == null: return 0.0 var f: Font = label.font if f == null: f = ThemeDB.fallback_font return height_of(f, label.text, label.font_size, fallback_line_px) # 增量 125(seam ⑩ 末尾 SetItemTextTailOwner):owner 后缀在参考端是与名字分开的 # pOwnerTextInstance,单独 GetTextSize。poc 只有一个合并 Label3D,故提供「用某 Label3D 的 # 字体 / 字号量任意子串」入口,让 ground_items 把名字子串、owner 子串分别度量。 # label 为 null -> 回退(宽 = 字符数 * fallback_char_px;高 = 空串 0 / 非空 fallback_line_px)。 static func string_width_like(label: Label3D, text: String, fallback_char_px := FALLBACK_CHAR_W_PX) -> float: if label == null: return float(text.length()) * fallback_char_px var f: Font = label.font if f == null: f = ThemeDB.fallback_font return width_of(f, text, label.font_size, fallback_char_px) static func string_height_like(label: Label3D, text: String, fallback_line_px := FALLBACK_LINE_H_PX) -> float: if text == "": return 0.0 if label == null: return fallback_line_px var f: Font = label.font if f == null: f = ThemeDB.fallback_font return height_of(f, text, label.font_size, fallback_line_px)