设置widget大小

从Geometry里可以获取两种size,Absolute和Local,这两者的关系是,在当前的渲染窗口中,AbsoluteSize/GetViewportScale() = LocalSize。这里的GetViewportScale()就是获取DPI系数。
Viewport上的Size是AbsoluteSize,因此GetViewportScale()是从LocalSize变换成AbsoluteSize的Scale。

参考 线性映射(linear mapping) ,s就是DPI缩放系数(通常值为0.67),(A, B)为LocalSize(Viewport坐标系描述),(X, Y)为ScreenSize(真实物理设备尺寸描述,不是所谓的ScreenSpace下的描述)。GetViewportSize()返回的是真实物理设备Screen坐标系下的尺寸描述。
UMG语境下,Absolute坐标与Local坐标都是在Viewport坐标系里的表述。
UMG LocalSpace, AbosoluteSpace, ScreenSpace, ViewportSpace
UE4技术杂谈——各种坐标空间转换与原理

关于Unreal Engine中Widget的Slot

各种Layouts与Widgets之间可能会有嵌套、组合之类的关系的。
比如,一个Layout引用一个widget,通常C++里可能会引用widget基类指针,UE4对这种使用指针的用法进行了建模,用Slot来代替指针的作用,Slot里比普通的指针提供了额外的一些信息,可以认为是一个强化版的指针,它包含双指针,一个指向这个Slot对应的Widget(C),一个指向该Widget(C)的ParentWidget(通常值就是this)。因此,每一个Widget里都有一个Slot成员(定义在Widget.h里的UPanelSlot* Slot;)。
阅读UPanelSlot* UPanelWidget::AddChild(UWidget* Content)函数源码,如下:
 UPanelSlot* PanelSlot = NewObject<UPanelSlot>(this, GetSlotClass(), NAME_None, NewObjectFlags);
 PanelSlot->Content = Content;
 PanelSlot->Parent = this;
 Content->Slot = PanelSlot;
这里能够清晰看到,Content作为一个UWidget,其Slot成员的Content属性指向该Widget自身,Parent属性指向该Widget的父Widget。即我们应该关注的是Slot树状结构,这棵树才是我们看到的UI布局的逻辑结构,树的节点都是Slot,每个Slot都有Slot->Content访问的是真正的Widget,Slot->Parent访问的是Widget的ParentWidget,同时注意,Parent类型是UPanelWidget*,还有Slot要想访问其父Slot,应该通过Slot->Parent->Slot
注意派生自UWidget的UPanelWidget体内增加了TArray<UPanelSlot*> Slots数据成员

线性映射(linear mapping)

在unreal engine里就是Clamp函数。
 问题:P的取值范围是[A, B],要将其线性对应到[X, Y]范围的Q点。已知P,求Q。
这种线性映射问题,其实就是一个缩放+平移的问题。先缩放一下使得两段范围宽度一致,再把两段范围的参照点平移对齐,就完成了映射过程。比如:将[A, B]缩放成[A', B'],其尺寸与[X, Y]相同,再把[A', B']平移叠到[X, Y]上,这样就完成了线性映射。将缩放和平移作用到P上,即可求出Q: \[Q = s * P + t\] s为缩放系数,t为平移量。将P=A,Q=X与P=B,Q=Y两组解分别带入上式,可得二元一次方程组: \[\left\{ \begin{array}{l} X = A * s + t \\ Y = B * s + t \end{array}\right.\] 求解可得: \[\left\{\begin{array}{l} s=\frac{Y-X}{B-A} \\ t=\frac{BX-AY}{B-A} \end{array} \right. \]

另一个角度的理解就是:先求AP在AB中所占比例t,线性映射中该比例不变,因此XQ在XY中所占比例也应为t,于是就有: \[\begin{align*} t = \frac{P-A}{B-A} \\ Q=t*(Y-X) + X \end{align*} \]