EG/ui/Builtin/RectTransform.py
2026-02-25 11:49:31 +08:00

86 lines
3.5 KiB
Python
Raw Permalink 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.

"""RectTransform - 一个轻量级的 Unity-like RectTransform 实现Python 层 MVP
提供 anchors/pivot/anchored_position/size_delta 的数据结构和
把相对锚点映射到像素矩形的计算方法。
此实现不修改底层 C++ LUI而是在 Python 层计算并把结果应用到
`LUIObject` 的 `left/top/width/height` 属性上。
"""
from typing import Tuple
class RectTransform(object):
def __init__(self,
anchor_min=(0.5, 0.5),
anchor_max=(0.5, 0.5),
pivot=(0.5, 0.5),
anchored_position=(0.0, 0.0),
size_delta=(100.0, 30.0)):
# 值域: anchor/pivot 为 0..1anchored_position/size_delta 为像素
self.anchor_min = tuple(anchor_min)
self.anchor_max = tuple(anchor_max)
self.pivot = tuple(pivot)
self.anchored_position = tuple(anchored_position)
self.size_delta = tuple(size_delta)
def compute_pixel_rect(self, parent_rect: Tuple[float, float, float, float]):
"""
将 RectTransform 转换为相对于父节点的像素矩形 (left, top, width, height)
parent_rect: (parent_left, parent_top, parent_width, parent_height)
"""
p_left, p_top, p_w, p_h = parent_rect
a_min_x = self.anchor_min[0]
a_min_y = self.anchor_min[1]
a_max_x = self.anchor_max[0]
a_max_y = self.anchor_max[1]
# 计算锚框的像素坐标left/top 和 right/bottom
anchor_left = p_left + a_min_x * p_w
anchor_right = p_left + a_max_x * p_w
anchor_top = p_top + a_min_y * p_h
anchor_bottom = p_top + a_max_y * p_h
# 宽高
if abs(a_max_x - a_min_x) < 1e-6:
# 固定锚点 -> 使用 size_delta.x
width = float(self.size_delta[0])
# anchored_position.x 表示相对于锚点框的位置(像素)
left = anchor_left + float(self.anchored_position[0]) - self.pivot[0] * width
else:
# 拉伸到锚框再加上 size_delta.x
width = (anchor_right - anchor_left) + float(self.size_delta[0])
# anchored_position.x 表示锚框内的像素偏移
left = anchor_left + float(self.anchored_position[0])
if abs(a_max_y - a_min_y) < 1e-6:
height = float(self.size_delta[1])
# 注意engine 中 top 增大表示向下,所以 anchored_position.y 保持像素系
top = anchor_top + float(self.anchored_position[1]) - self.pivot[1] * height
else:
height = (anchor_bottom - anchor_top) + float(self.size_delta[1])
top = anchor_top + float(self.anchored_position[1])
return (left, top, width, height)
def apply_to_lui(self, lui_obj, parent_rect: Tuple[float, float, float, float]):
"""计算并应用到给定的 LUIObject设置 left/top/width/height"""
left, top, width, height = self.compute_pixel_rect(parent_rect)
try:
lui_obj.left = left
lui_obj.top = top
lui_obj.width = width
lui_obj.height = height
except Exception:
# 忽略不能设置的属性,调用者应保证对象支持这些属性
pass
def to_dict(self):
return {
'anchor_min': tuple(self.anchor_min),
'anchor_max': tuple(self.anchor_max),
'pivot': tuple(self.pivot),
'anchored_position': tuple(self.anchored_position),
'size_delta': tuple(self.size_delta),
}