before adapt to web

This commit is contained in:
bridge
2025-11-20 01:02:31 +08:00
parent c5e2c2ff6d
commit 32cb34c173
4 changed files with 185 additions and 101 deletions

View File

@@ -1,39 +1,8 @@
from typing import List, Optional, Tuple, Dict
from src.utils.text_wrap import wrap_text_by_pixels
from .rendering import map_pixel_size
def _wrap_text_by_pixels(font, text: str, max_width_px: int) -> List[str]:
"""
按像素宽度对单行文本进行硬换行,适配中英文混排(逐字符测量)。
"""
if not text:
return [""]
# 先处理显式换行符 \n避免被当作乱码字符渲染
logical_lines = str(text).split('\n')
result: List[str] = []
# 对每个逻辑行分别进行像素宽度换行
for logical_line in logical_lines:
if not logical_line:
result.append("")
continue
current = ""
for ch in logical_line:
test = current + ch
w, _ = font.size(test)
if w <= max_width_px:
current = test
else:
if current:
result.append(current)
current = ch
if current:
result.append(current)
return result if result else [""]
def draw_sidebar(
pygame_mod,
screen,
@@ -86,7 +55,8 @@ def draw_sidebar(
# 描述文字(自动换行)
usable_width = phenomenon_width
desc_lines = _wrap_text_by_pixels(font, current_phenomenon.desc, usable_width)
# 使用统一的 wrap_text_by_pixels
desc_lines = wrap_text_by_pixels(font, current_phenomenon.desc, usable_width)
for line in desc_lines:
line_surf = font.render(line, True, colors["event_text"])
screen.blit(line_surf, (phenomenon_x, phenomenon_y))
@@ -163,7 +133,8 @@ def draw_sidebar(
# 从最新事件开始,逐条向下渲染,超出底部则停止
for event in reversed(events):
event_text = str(event)
wrapped_lines = _wrap_text_by_pixels(font, event_text, usable_width)
# 使用统一的 wrap_text_by_pixels
wrapped_lines = wrap_text_by_pixels(font, event_text, usable_width)
for line in wrapped_lines:
event_surf = font.render(line, True, colors["event_text"])
screen.blit(event_surf, (title_x, event_y))
@@ -184,5 +155,3 @@ def draw_sidebar(
__all__ = ["draw_sidebar"]

View File

@@ -1,14 +1,14 @@
import math
from typing import List, Optional, Tuple, Callable
from src.classes.avatar import Avatar
from src.utils.text_wrap import wrap_text
from src.utils.text_wrap import wrap_text_by_pixels
def wrap_lines_for_tooltip(lines: List[str], max_chars_per_line: int = 28) -> List[str]:
def wrap_lines_for_tooltip(font, lines: List[str], max_width_px: int = 320) -> List[str]:
"""
将一组 tooltip 行进行字符级换行:
将一组 tooltip 行进行像素级自动换行:
- 对形如 "前缀: 内容" 的行,仅对内容部分换行,并在续行添加两个空格缩进
- 其他行超过宽度则直接按宽度切分
- 其他行超过宽度则直接按像素宽度切分
"""
wrapped: List[str] = []
for line in lines:
@@ -17,23 +17,38 @@ def wrap_lines_for_tooltip(lines: List[str], max_chars_per_line: int = 28) -> Li
if split_idx != -1:
prefix = line[: split_idx + 2]
content = line[split_idx + 2 :]
segs = wrap_text(content, max_chars_per_line)
prefix_w, _ = font.size(prefix)
indent_str = " "
indent_w, _ = font.size(indent_str)
# 内容的第一行允许宽度 = 总宽 - 前缀宽
# 内容的后续行允许宽度 = 总宽 - 缩进宽
content_first_w = max_width_px - prefix_w
content_rest_w = max_width_px - indent_w
# 边界保护:如果前缀特别长导致第一行没空间,就强制让它换行(给一个合理的最小值)
# 或者直接让它等于后续行宽度(这会造成视觉溢出,但比死循环好)
if content_first_w < 20:
content_first_w = content_rest_w
segs = wrap_text_by_pixels(font, content, content_rest_w, first_line_max_width_px=content_first_w)
if segs:
wrapped.append(prefix + segs[0])
for seg in segs[1:]:
wrapped.append(" " + seg)
wrapped.append(indent_str + seg)
else:
# 内容为空的情况
wrapped.append(line)
continue
# 无前缀情形:必要时整行切分
if len(line) > max_chars_per_line:
wrapped.extend(wrap_text(line, max_chars_per_line))
else:
wrapped.append(line)
# 无前缀情形:直接换行
wrapped.extend(wrap_text_by_pixels(font, line, max_width_px))
return wrapped
def draw_grid(pygame_mod, screen, colors, map_obj, ts: int, m: int, top_offset: int = 0):
grid_color = colors["grid"]
for gx in range(map_obj.width + 1):
@@ -333,7 +348,7 @@ def draw_avatars_and_pick_hover(
return hovered, candidate_avatars
def draw_tooltip(pygame_mod, screen, colors, lines: List[str], mouse_x: int, mouse_y: int, font, min_width: int = 260, top_limit: int = 0):
def draw_tooltip(pygame_mod, screen, colors, lines: List[str], mouse_x: int, mouse_y: int, font, min_width: int = 320, top_limit: int = 0):
"""
绘制tooltip支持颜色标记格式<color:R,G,B>text</color>
"""
@@ -433,18 +448,20 @@ def _render_colored_text(pygame_mod, font, text: str, default_color) -> object:
return combined
def draw_tooltip_for_avatar(pygame_mod, screen, colors, font, avatar: Avatar, tooltip_min_width: int = 260, status_bar_height: int = 32):
# 改为从 Avatar.get_hover_info 获取信息行,避免前端重复拼接
def draw_tooltip_for_avatar(pygame_mod, screen, colors, font, avatar: Avatar, tooltip_min_width: int = 320, status_bar_height: int = 32):
# 从 Avatar.get_hover_info 获取信息行
lines = avatar.get_hover_info()
draw_tooltip(pygame_mod, screen, colors, lines, *pygame_mod.mouse.get_pos(), font, min_width=tooltip_min_width, top_limit=status_bar_height)
# 使用 wrap_lines_for_tooltip 进行像素级自动换行
wrapped_lines = wrap_lines_for_tooltip(font, lines, max_width_px=tooltip_min_width)
draw_tooltip(pygame_mod, screen, colors, wrapped_lines, *pygame_mod.mouse.get_pos(), font, min_width=tooltip_min_width, top_limit=status_bar_height)
def draw_tooltip_for_region(pygame_mod, screen, colors, font, region, mouse_x: int, mouse_y: int, tooltip_min_width: int = 260, status_bar_height: int = 32):
def draw_tooltip_for_region(pygame_mod, screen, colors, font, region, mouse_x: int, mouse_y: int, tooltip_min_width: int = 320, status_bar_height: int = 32):
if region is None:
return
# 改为调用 region.get_hover_info(),并统一用 wrap_lines_for_tooltip 进行换行
# 调用 region.get_hover_info(),并统一用 wrap_lines_for_tooltip 进行换行
lines = region.get_hover_info()
wrapped_lines = wrap_lines_for_tooltip(lines, 28)
wrapped_lines = wrap_lines_for_tooltip(font, lines, max_width_px=tooltip_min_width)
draw_tooltip(pygame_mod, screen, colors, wrapped_lines, mouse_x, mouse_y, font, min_width=tooltip_min_width, top_limit=status_bar_height)