Files
cultivation-world-simulator/src/front/layout.py
2025-11-11 18:42:38 +08:00

138 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""动态布局计算模块
根据屏幕分辨率动态计算所有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"]