add flexible front end

This commit is contained in:
bridge
2025-11-11 18:42:38 +08:00
parent ba536978e7
commit ed4174d5ed
7 changed files with 218 additions and 49 deletions

137
src/front/layout.py Normal file
View File

@@ -0,0 +1,137 @@
"""动态布局计算模块
根据屏幕分辨率动态计算所有UI组件的尺寸实现自适应布局。
"""
from typing import NamedTuple
class LayoutConfig(NamedTuple):
"""布局配置类,包含所有动态计算的尺寸参数"""
# 屏幕尺寸
screen_width: int
screen_height: int
# 地图相关
tile_size: int
margin: int
# UI组件尺寸
status_bar_height: int
sidebar_width: int
# 字体尺寸
font_size_normal: int # 普通文本原14
font_size_medium: int # 中等文本原16
font_size_large: int # 大文本原18
font_size_tooltip: int # tooltip文本原14
# 其他动态参数
avatar_size: int # avatar图像大小
tooltip_min_width: int # tooltip最小宽度
def clamp(value: float, min_val: float, max_val: float) -> int:
"""将值限制在指定范围内并返回整数"""
return int(max(min_val, min(max_val, value)))
def calculate_layout(screen_width: int, screen_height: int, map_width: int = 56, map_height: int = 40) -> LayoutConfig:
"""
根据屏幕分辨率计算所有布局参数
Args:
screen_width: 屏幕宽度(像素)
screen_height: 屏幕高度(像素)
map_width: 地图宽度(格子数)
map_height: 地图高度(格子数)
Returns:
LayoutConfig: 包含所有布局参数的配置对象
"""
# 1. 计算固定UI组件尺寸使用混合策略百分比 + 最小最大值限制)
# 状态栏高度屏幕高度的2.5%限制在24-48px
status_bar_height = clamp(screen_height * 0.025, 24, 48)
# 侧边栏宽度屏幕宽度的18%限制在280-420px
sidebar_width = clamp(screen_width * 0.18, 280, 420)
# 边距屏幕较短边的0.8%限制在6-16px
margin = clamp(min(screen_width, screen_height) * 0.008, 6, 16)
# 2. 计算地图区域可用空间
available_width = screen_width - sidebar_width - margin * 2
available_height = screen_height - status_bar_height - margin * 2
# 3. 计算tile_size保证完整显示地图
tile_size_by_width = available_width / map_width
tile_size_by_height = available_height / map_height
# 取较小值确保两个方向都能完整显示并限制最大值为64px防止超大屏幕显示异常
tile_size = clamp(min(tile_size_by_width, tile_size_by_height), 1, 64)
# 4. 计算字体尺寸根据tile_size动态缩放
# 基准tile_size=32时字体大小为 14/16/18
font_scale = tile_size / 32.0
font_size_normal = max(14, int(14 * font_scale)) # 最小14px保证可读性
font_size_medium = max(16, int(16 * font_scale))
font_size_large = max(18, int(18 * font_scale))
font_size_tooltip = max(14, int(14 * font_scale))
# 5. 计算avatar尺寸与原来的公式保持一致但基于动态tile_size
avatar_size = max(20, int((tile_size * 4 // 3) * 1.8))
# 6. 计算tooltip最小宽度原来是260px按比例缩放
tooltip_min_width = max(200, int(260 * font_scale))
return LayoutConfig(
screen_width=screen_width,
screen_height=screen_height,
tile_size=tile_size,
margin=margin,
status_bar_height=status_bar_height,
sidebar_width=sidebar_width,
font_size_normal=font_size_normal,
font_size_medium=font_size_medium,
font_size_large=font_size_large,
font_size_tooltip=font_size_tooltip,
avatar_size=avatar_size,
tooltip_min_width=tooltip_min_width,
)
def get_fullscreen_resolution(pygame_mod) -> tuple[int, int]:
"""
获取当前显示器的可用分辨率(排除任务栏)
Args:
pygame_mod: pygame模块
Returns:
(width, height): 可用屏幕分辨率
"""
# 初始化video模块如果还未初始化
if not pygame_mod.get_init():
pygame_mod.init()
# 获取显示器信息
info = pygame_mod.display.Info()
# 获取桌面可用区域(排除任务栏等)
# 在Windows上current_w/h 是全屏分辨率
# 我们需要预留一些空间给任务栏通常在底部约40-60像素
width = info.current_w
height = info.current_h
# 为任务栏预留空间约40-50像素取决于缩放比例
# 这是一个保守的估计,确保窗口不会覆盖任务栏
taskbar_height = max(40, int(height * 0.04)) # 约4%的高度
return width, height - taskbar_height
__all__ = ["LayoutConfig", "calculate_layout", "get_fullscreen_resolution"]