86 lines
3.5 KiB
Python
86 lines
3.5 KiB
Python
"""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..1,anchored_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),
|
||
}
|