feat: Initial commit
This commit is contained in:
8
Assets/Cryville.Common/Unity/UI.meta
Normal file
8
Assets/Cryville.Common/Unity/UI.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad96c636bfa80024f8427b7755b56639
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
113
Assets/Cryville.Common/Unity/UI/AspectRatioLayoutElement.cs
Normal file
113
Assets/Cryville.Common/Unity/UI/AspectRatioLayoutElement.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="ILayoutElement" /> that takes the length of one axis to compute the preferred length of the other axis with respect to a aspect ratio.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Layout/Aspect Ratio Layout Element")]
|
||||
[ExecuteAlways]
|
||||
public class AspectRatioLayoutElement : UIBehaviour, ILayoutElement {
|
||||
[SerializeField]
|
||||
[Tooltip("The aspect ratio. Width divided by height.")]
|
||||
private float m_aspectRatio = 1;
|
||||
/// <summary>
|
||||
/// The aspect ratio. Width divided by height.
|
||||
/// </summary>
|
||||
public float AspectRatio {
|
||||
get { return m_aspectRatio; }
|
||||
set { SetProperty(ref m_aspectRatio, value); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Whether to compute the length of the y axis.")]
|
||||
private bool m_isVertical = false;
|
||||
/// <summary>
|
||||
/// Whether to compute the length of the y axis.
|
||||
/// </summary>
|
||||
public bool IsVertical {
|
||||
get { return m_isVertical; }
|
||||
set { SetProperty(ref m_isVertical, value); }
|
||||
}
|
||||
|
||||
private void SetProperty<T>(ref T prop, T value) {
|
||||
if (Equals(prop, value)) return;
|
||||
prop = value;
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public float minWidth {
|
||||
get {
|
||||
return m_isVertical ? -1 : (transform as RectTransform).rect.height * m_aspectRatio;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public float preferredWidth { get { return minWidth; } }
|
||||
/// <inheritdoc />
|
||||
public float flexibleWidth { get { return -1; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public float minHeight {
|
||||
get {
|
||||
return m_isVertical ? (transform as RectTransform).rect.width / m_aspectRatio : -1;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public float preferredHeight { get { return minHeight; } }
|
||||
/// <inheritdoc />
|
||||
public float flexibleHeight { get { return -1; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int layoutPriority { get { return 1; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CalculateLayoutInputHorizontal() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CalculateLayoutInputVertical() { }
|
||||
|
||||
protected override void OnEnable() {
|
||||
base.OnEnable();
|
||||
SetDirty();
|
||||
}
|
||||
protected override void OnBeforeTransformParentChanged() {
|
||||
base.OnBeforeTransformParentChanged();
|
||||
SetDirty();
|
||||
}
|
||||
protected override void OnTransformParentChanged() {
|
||||
base.OnTransformParentChanged();
|
||||
SetDirty();
|
||||
}
|
||||
protected override void OnDidApplyAnimationProperties() {
|
||||
base.OnDidApplyAnimationProperties();
|
||||
SetDirty();
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate() {
|
||||
base.OnValidate();
|
||||
SetDirty();
|
||||
}
|
||||
#endif
|
||||
protected override void OnDisable() {
|
||||
SetDirty();
|
||||
base.OnDisable();
|
||||
}
|
||||
protected override void OnRectTransformDimensionsChange() {
|
||||
base.OnRectTransformDimensionsChange();
|
||||
SetDirty();
|
||||
}
|
||||
bool _delayedSetDirty;
|
||||
private void SetDirty() {
|
||||
if (!IsActive()) return;
|
||||
if (CanvasUpdateRegistry.IsRebuildingLayout()) _delayedSetDirty = true;
|
||||
else LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
|
||||
}
|
||||
void Update() {
|
||||
if (!_delayedSetDirty) return;
|
||||
_delayedSetDirty = false;
|
||||
LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96276a3ffc8f32c4fbb7035a6fb28e74
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,24 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="DockLayoutGroup" /> that sets the aspect ratio of the docking element.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Layout/Dock Aspect Ratio Layout Group")]
|
||||
public sealed class DockAspectRatioLayoutGroup : DockLayoutGroup {
|
||||
[SerializeField]
|
||||
[Tooltip("The aspect ratio of the docking element.")]
|
||||
private float m_dockAspectRatio = 1;
|
||||
/// <summary>
|
||||
/// The aspect ratio of the docking element.
|
||||
/// </summary>
|
||||
public float DockAspectRatio {
|
||||
get { return m_dockAspectRatio; }
|
||||
set { base.SetProperty(ref m_dockAspectRatio, value); }
|
||||
}
|
||||
|
||||
protected override float GetDockElementSize(Vector2 groupSize) {
|
||||
return groupSize.y * m_dockAspectRatio;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9023f24d2fe04fe45bf66a9d029591c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
136
Assets/Cryville.Common/Unity/UI/DockLayoutGroup.cs
Normal file
136
Assets/Cryville.Common/Unity/UI/DockLayoutGroup.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="LayoutGroup" /> that docks its first child element to one side.
|
||||
/// </summary>
|
||||
public abstract class DockLayoutGroup : LayoutGroup {
|
||||
/// <summary>
|
||||
/// The dock side.
|
||||
/// </summary>
|
||||
public enum Side {
|
||||
/// <summary>
|
||||
/// Top.
|
||||
/// </summary>
|
||||
Top = 0,
|
||||
/// <summary>
|
||||
/// Right.
|
||||
/// </summary>
|
||||
Right = 1,
|
||||
/// <summary>
|
||||
/// Bottom.
|
||||
/// </summary>
|
||||
Bottom = 2,
|
||||
/// <summary>
|
||||
/// Left.
|
||||
/// </summary>
|
||||
Left = 3,
|
||||
}
|
||||
[SerializeField]
|
||||
[Tooltip("The docking side of the first child element.")]
|
||||
private Side m_side;
|
||||
/// <summary>
|
||||
/// The docking side of the first child element.
|
||||
/// </summary>
|
||||
public Side DockSide {
|
||||
get { return m_side; }
|
||||
set { SetProperty(ref m_side, value); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The slide index. The children slide along the cross axis.")]
|
||||
private float m_slideIndex;
|
||||
/// <summary>
|
||||
/// The slide index. The children slide along the axis.
|
||||
/// </summary>
|
||||
public float SlideIndex {
|
||||
get { return m_slideIndex; }
|
||||
set { SetProperty(ref m_slideIndex, value); }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); CalcAlongAxis(0); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void CalculateLayoutInputVertical() { CalcAlongAxis(1); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void SetLayoutVertical() { SetChildrenAlongAxis(1); }
|
||||
|
||||
private void CalcAlongAxis(int axis) {
|
||||
int isHorizontal = (int)m_side & 1;
|
||||
if ((isHorizontal ^ axis) == 1) {
|
||||
SetLayoutInputForAxis(0, 0, 1, axis); // TODO
|
||||
}
|
||||
else {
|
||||
float padding = isHorizontal == 0 ? m_Padding.horizontal : m_Padding.vertical;
|
||||
float totalMin = 0, totalPreferred = 0, totalFlexible = 0;
|
||||
for (int i = 0; i < rectChildren.Count; i++) {
|
||||
GetChildSizes(rectChildren[i], axis, out float min, out float preferred, out float flexible);
|
||||
if (min > totalMin) totalMin = min;
|
||||
if (preferred > totalPreferred) totalPreferred = preferred;
|
||||
if (flexible > totalFlexible) totalFlexible = flexible;
|
||||
}
|
||||
SetLayoutInputForAxis(totalMin + padding, totalPreferred + padding, totalFlexible, axis);
|
||||
}
|
||||
}
|
||||
private void GetChildSizes(RectTransform child, int axis, out float min, out float preferred, out float flexible) {
|
||||
min = LayoutUtility.GetMinSize(child, axis);
|
||||
preferred = LayoutUtility.GetPreferredSize(child, axis);
|
||||
flexible = LayoutUtility.GetFlexibleSize(child, axis);
|
||||
}
|
||||
|
||||
private float GetSlidePosition(float groupHeight, float dockHeight) {
|
||||
bool d = Mathf.FloorToInt(m_slideIndex - Mathf.Floor(m_slideIndex / 2) * 2) == 0;
|
||||
int l = Mathf.FloorToInt(m_slideIndex / 2);
|
||||
float p = m_slideIndex - Mathf.Floor(m_slideIndex);
|
||||
if (d) return l * groupHeight + p * dockHeight;
|
||||
else return l * groupHeight + dockHeight + p * (groupHeight - dockHeight);
|
||||
}
|
||||
|
||||
private void SetChildrenAlongAxis(int axis) {
|
||||
int isHorizontal = (int)m_side & 1;
|
||||
bool isReversed = m_side == Side.Right || m_side == Side.Bottom;
|
||||
var rect = rectTransform.rect;
|
||||
if ((isHorizontal ^ axis) == 1) {
|
||||
float p0 = isHorizontal == 1 ? m_Padding.left : m_Padding.top;
|
||||
float p1 = isHorizontal == 1 ? m_Padding.right : m_Padding.bottom;
|
||||
var gs = rect.size - new Vector2(m_Padding.horizontal, m_Padding.vertical);
|
||||
if (isHorizontal == 0) gs = new Vector2(gs.y, gs.x);
|
||||
if (rectChildren.Count == 1) {
|
||||
SetChildAlongAxis(rectChildren[0], axis, p0, gs.x);
|
||||
}
|
||||
else {
|
||||
float s1 = GetDockElementSize(gs);
|
||||
float s0 = GetSlidePosition(gs.x, s1);
|
||||
float a1 = (isHorizontal == 0 ? rect.height : rect.width) - p0 - p1;
|
||||
for (int i = 0; i < rectChildren.Count; i++) {
|
||||
var c = rectChildren[i];
|
||||
bool d = i % 2 == 0;
|
||||
int l = i / 2;
|
||||
if (isReversed)
|
||||
SetChildAlongAxis(c, axis, (d ? a1 - s1 + p0 : p0) - a1 * l + s0, d ? s1 : a1 - s1);
|
||||
else
|
||||
SetChildAlongAxis(c, axis, (d ? p0 : s1 + p0) - s0 + a1 * l, d ? s1 : a1 - s1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
float p0 = isHorizontal == 0 ? m_Padding.left : m_Padding.top;
|
||||
float p1 = isHorizontal == 0 ? m_Padding.right : m_Padding.bottom;
|
||||
var height = (isHorizontal == 1 ? rect.height : rect.width) - p0 - p1;
|
||||
for (int i = 0; i < rectChildren.Count; i++) {
|
||||
SetChildAlongAxis(rectChildren[i], axis, p0, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the first child element along the axis.
|
||||
/// </summary>
|
||||
/// <param name="groupSize">The size of the layout group.</param>
|
||||
/// <returns></returns>
|
||||
protected abstract float GetDockElementSize(Vector2 groupSize);
|
||||
}
|
||||
}
|
11
Assets/Cryville.Common/Unity/UI/DockLayoutGroup.cs.meta
Normal file
11
Assets/Cryville.Common/Unity/UI/DockLayoutGroup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb94861327965934cb429511060d45fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,24 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="DockLayoutGroup" /> that sets the occupied ratio of the docking element.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Layout/Dock Occupied Ratio Layout Group")]
|
||||
public sealed class DockOccupiedRatioLayoutGroup : DockLayoutGroup {
|
||||
[SerializeField]
|
||||
[Tooltip("The occupied ratio of the docking element.")]
|
||||
private float m_dockOccupiedRatio = 1;
|
||||
/// <summary>
|
||||
/// The occupied ratio of the docking element.
|
||||
/// </summary>
|
||||
public float DockOccupiedRatio {
|
||||
get { return m_dockOccupiedRatio; }
|
||||
set { base.SetProperty(ref m_dockOccupiedRatio, value); }
|
||||
}
|
||||
|
||||
protected override float GetDockElementSize(Vector2 groupSize) {
|
||||
return groupSize.x * m_dockOccupiedRatio;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bbf3330df0a07e46bcdf0b3c4879ecf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
97
Assets/Cryville.Common/Unity/UI/FlowLayoutGroup.cs
Normal file
97
Assets/Cryville.Common/Unity/UI/FlowLayoutGroup.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
[AddComponentMenu("Layout/Flow Layout Group")]
|
||||
public class FlowLayoutGroup : LayoutGroup {
|
||||
[SerializeField] Vector2 m_spacing;
|
||||
public Vector2 Spacing {
|
||||
get { return m_spacing; }
|
||||
set { SetProperty(ref m_spacing, value); }
|
||||
}
|
||||
|
||||
[SerializeField][Range(0, 1)] float m_itemAlignmentRatio;
|
||||
public float ItemAlignmentRatio {
|
||||
get { return m_itemAlignmentRatio; }
|
||||
set { SetProperty(ref m_itemAlignmentRatio, value); }
|
||||
}
|
||||
|
||||
[SerializeField][Range(0, 1)] float m_itemAlignmentStretchingRatio;
|
||||
public float ItemAlignmentStretchingRatio {
|
||||
get { return m_itemAlignmentStretchingRatio; }
|
||||
set { SetProperty(ref m_itemAlignmentStretchingRatio, value); }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); CalcAlongAxis(0); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void CalculateLayoutInputVertical() { CalcAlongAxis(1); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void SetLayoutVertical() { SetChildrenAlongAxis(1); }
|
||||
|
||||
void CalcAlongAxis(int axis) {
|
||||
if (axis == 0) {
|
||||
SetLayoutInputForAxis(0, 0, 1, axis); // TODO
|
||||
}
|
||||
else {
|
||||
float width = rectTransform.rect.width - padding.horizontal;
|
||||
float x = 0, y = padding.top;
|
||||
float lineHeight = 0;
|
||||
for (int i = 0; i < rectChildren.Count; i++) {
|
||||
RectTransform child = rectChildren[i];
|
||||
float minWidth = LayoutUtility.GetMinWidth(child);
|
||||
float childWidth = Math.Max(minWidth, Math.Min(width, LayoutUtility.GetPreferredWidth(child)));
|
||||
float childHeight = LayoutUtility.GetPreferredHeight(child);
|
||||
|
||||
if (childWidth > width - x) {
|
||||
x = 0;
|
||||
if (i > 0) y += lineHeight + m_spacing.y;
|
||||
lineHeight = 0;
|
||||
}
|
||||
|
||||
x += childWidth + m_spacing.x;
|
||||
if (childHeight > lineHeight) lineHeight = childHeight;
|
||||
}
|
||||
SetLayoutInputForAxis(y + lineHeight, y + lineHeight, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void SetChildrenAlongAxis(int axis) {
|
||||
float width = rectTransform.rect.width - padding.horizontal;
|
||||
float x = 0, y = padding.top;
|
||||
float lineHeight = 0;
|
||||
int firstItemIndexOfLine = 0;
|
||||
for (int i = 0; i < rectChildren.Count; i++) {
|
||||
RectTransform child = rectChildren[i];
|
||||
float minWidth = LayoutUtility.GetMinWidth(child);
|
||||
float childWidth = Math.Max(minWidth, Math.Min(width, LayoutUtility.GetPreferredWidth(child)));
|
||||
float childHeight = LayoutUtility.GetPreferredHeight(child);
|
||||
|
||||
if (childWidth > width - x) {
|
||||
AlignItemsInLine(firstItemIndexOfLine, i, y, lineHeight);
|
||||
x = 0;
|
||||
if (i > 0) y += lineHeight + m_spacing.y;
|
||||
lineHeight = 0;
|
||||
firstItemIndexOfLine = i;
|
||||
}
|
||||
|
||||
SetChildAlongAxis(child, 0, x + padding.left, childWidth);
|
||||
SetChildAlongAxis(child, 1, y, childHeight);
|
||||
|
||||
x += childWidth + m_spacing.x;
|
||||
if (childHeight > lineHeight) lineHeight = childHeight;
|
||||
}
|
||||
AlignItemsInLine(firstItemIndexOfLine, rectChildren.Count, y, lineHeight);
|
||||
}
|
||||
void AlignItemsInLine(int startIndex, int endIndex, float y, float lineHeight) {
|
||||
for (int i = startIndex; i < endIndex; i++) {
|
||||
RectTransform child = rectChildren[i];
|
||||
float childHeight = LayoutUtility.GetPreferredHeight(child) * (1 - m_itemAlignmentStretchingRatio) + lineHeight * m_itemAlignmentStretchingRatio;
|
||||
SetChildAlongAxis(child, 1, y + (lineHeight - childHeight) * m_itemAlignmentRatio, childHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville.Common/Unity/UI/FlowLayoutGroup.cs.meta
Normal file
11
Assets/Cryville.Common/Unity/UI/FlowLayoutGroup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ce1debad67438245a6e00e503975beb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
94
Assets/Cryville.Common/Unity/UI/SingleLayoutGroup.cs
Normal file
94
Assets/Cryville.Common/Unity/UI/SingleLayoutGroup.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
[AddComponentMenu("Layout/Single Layout Group")]
|
||||
[ExecuteAlways]
|
||||
public class SingleLayoutGroup : LayoutGroup {
|
||||
[SerializeField]
|
||||
protected bool m_ChildForceExpandWidth = true;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_ChildForceExpandHeight = true;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_ChildControlWidth = true;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_ChildControlHeight = true;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_ChildScaleWidth;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_ChildScaleHeight;
|
||||
|
||||
public override void CalculateLayoutInputHorizontal() {
|
||||
base.CalculateLayoutInputHorizontal();
|
||||
CalcAlongAxis(0);
|
||||
}
|
||||
public override void CalculateLayoutInputVertical() { CalcAlongAxis(1); }
|
||||
public override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); }
|
||||
public override void SetLayoutVertical() { SetChildrenAlongAxis(1); }
|
||||
|
||||
protected void CalcAlongAxis(int axis) {
|
||||
float combinedPadding = (axis == 0) ? padding.horizontal : padding.vertical;
|
||||
bool controlSize = (axis == 0) ? m_ChildControlWidth : m_ChildControlHeight;
|
||||
bool useScale = (axis == 0) ? m_ChildScaleWidth : m_ChildScaleHeight;
|
||||
bool childForceExpandSize = (axis == 0) ? m_ChildForceExpandWidth : m_ChildForceExpandHeight;
|
||||
float totalMin = combinedPadding;
|
||||
float totalPreferred = combinedPadding;
|
||||
float totalFlexible = 0f;
|
||||
RectTransform child = rectChildren[0];
|
||||
GetChildSizes(child, axis, controlSize, childForceExpandSize, out var min, out var preferred, out var flexible);
|
||||
if (useScale) {
|
||||
float scaleFactor = child.localScale[axis];
|
||||
min *= scaleFactor;
|
||||
preferred *= scaleFactor;
|
||||
flexible *= scaleFactor;
|
||||
}
|
||||
totalMin = Mathf.Max(min + combinedPadding, totalMin);
|
||||
totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred);
|
||||
totalFlexible = Mathf.Max(flexible, totalFlexible);
|
||||
totalPreferred = Mathf.Max(totalMin, totalPreferred);
|
||||
SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, axis);
|
||||
}
|
||||
|
||||
protected void SetChildrenAlongAxis(int axis) {
|
||||
float size = rectTransform.rect.size[axis];
|
||||
bool controlSize = (axis == 0) ? m_ChildControlWidth : m_ChildControlHeight;
|
||||
bool useScale = (axis == 0) ? m_ChildScaleWidth : m_ChildScaleHeight;
|
||||
bool childForceExpandSize = (axis == 0) ? m_ChildForceExpandWidth : m_ChildForceExpandHeight;
|
||||
float alignmentOnAxis = GetAlignmentOnAxis(axis);
|
||||
float innerSize = size - ((axis == 0) ? padding.horizontal : padding.vertical);
|
||||
RectTransform child = rectChildren[0];
|
||||
GetChildSizes(child, axis, controlSize, childForceExpandSize, out var min2, out var preferred2, out var flexible2);
|
||||
float scaleFactor2 = useScale ? child.localScale[axis] : 1f;
|
||||
float requiredSpace = Mathf.Clamp(innerSize, min2, (flexible2 > 0f) ? size : preferred2);
|
||||
float startOffset = GetStartOffset(axis, requiredSpace * scaleFactor2);
|
||||
if (controlSize) {
|
||||
SetChildAlongAxisWithScale(child, axis, startOffset, requiredSpace, scaleFactor2);
|
||||
}
|
||||
else {
|
||||
float offsetInCell2 = (requiredSpace - child.sizeDelta[axis]) * alignmentOnAxis;
|
||||
SetChildAlongAxisWithScale(child, axis, startOffset + offsetInCell2, scaleFactor2);
|
||||
}
|
||||
}
|
||||
|
||||
void GetChildSizes(RectTransform child, int axis, bool controlSize, bool childForceExpand, out float min, out float preferred, out float flexible) {
|
||||
if (!controlSize) {
|
||||
min = child.sizeDelta[axis];
|
||||
preferred = min;
|
||||
flexible = 0f;
|
||||
}
|
||||
else {
|
||||
min = LayoutUtility.GetMinSize(child, axis);
|
||||
preferred = LayoutUtility.GetPreferredSize(child, axis);
|
||||
flexible = LayoutUtility.GetFlexibleSize(child, axis);
|
||||
}
|
||||
if (childForceExpand) {
|
||||
flexible = Mathf.Max(flexible, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville.Common/Unity/UI/SingleLayoutGroup.cs.meta
Normal file
11
Assets/Cryville.Common/Unity/UI/SingleLayoutGroup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21255a16576b76f4280a765b43a4ae1c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
80
Assets/Cryville.Common/Unity/UI/TMPLocalizedText.cs
Normal file
80
Assets/Cryville.Common/Unity/UI/TMPLocalizedText.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using Cryville.Common.Font;
|
||||
using Cryville.Culture;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TextCore.LowLevel;
|
||||
using UnityEngine.TextCore.Text;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
[RequireComponent(typeof(TMP_Text))]
|
||||
public class TMPLocalizedText : MonoBehaviour {
|
||||
public static Shader DefaultShader;
|
||||
public static FontMatcher FontMatcher;
|
||||
public static int MaxFallbackCount = 4;
|
||||
|
||||
static readonly Dictionary<CultureInfo, FontAsset> _cachedFonts = new();
|
||||
|
||||
[SerializeField]
|
||||
Shader m_shader;
|
||||
|
||||
public TMP_Text Text { get; private set; }
|
||||
void Awake() {
|
||||
Text = GetComponent<TMP_Text>();
|
||||
}
|
||||
|
||||
public void SetText(string text, CultureInfo culture = null) {
|
||||
Text.text = text;
|
||||
SetCulture(culture ?? CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
void SetCulture(CultureInfo culture) {
|
||||
if (FontMatcher == null) return;
|
||||
string cultureName = culture.Name;
|
||||
if (string.IsNullOrEmpty(cultureName)) cultureName = CultureInfo.CurrentCulture.Name;
|
||||
if (!_cachedFonts.TryGetValue(culture, out var font)) {
|
||||
foreach (var typeface in FontMatcher.MatchLanguage(new LanguageId(cultureName), true)) {
|
||||
try {
|
||||
var ifont = CreateFontAsset(typeface.File.FullName, typeface.IndexInFile);
|
||||
if (m_shader) ifont.material.shader = m_shader;
|
||||
else if (DefaultShader) ifont.material.shader = DefaultShader;
|
||||
if (font == null) {
|
||||
font = ifont;
|
||||
if (MaxFallbackCount <= 0) break;
|
||||
}
|
||||
else {
|
||||
font.fallbackFontAssetTable ??= new List<FontAsset>();
|
||||
font.fallbackFontAssetTable.Add(ifont);
|
||||
if (font.fallbackFontAssetTable.Count >= MaxFallbackCount) break;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
_cachedFonts.Add(culture, font);
|
||||
}
|
||||
Text.font = font;
|
||||
}
|
||||
|
||||
static MethodInfo _methodCreateFontAsset;
|
||||
static readonly object[] _paramsCreateFontAsset = new object[] { null, null, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024, Type.Missing, Type.Missing };
|
||||
static FontAsset CreateFontAsset(string path, int index) {
|
||||
if (_methodCreateFontAsset == null) {
|
||||
_methodCreateFontAsset = typeof(FontAsset).GetMethod(
|
||||
"CreateFontAsset", BindingFlags.Static | BindingFlags.NonPublic, null,
|
||||
new Type[] {
|
||||
typeof(string), typeof(int), typeof(int), typeof(int),
|
||||
typeof(GlyphRenderMode), typeof(int), typeof(int),
|
||||
typeof(AtlasPopulationMode), typeof(bool)
|
||||
},
|
||||
null
|
||||
);
|
||||
}
|
||||
_paramsCreateFontAsset[0] = path;
|
||||
_paramsCreateFontAsset[1] = index;
|
||||
return (FontAsset)_methodCreateFontAsset.Invoke(null, _paramsCreateFontAsset);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville.Common/Unity/UI/TMPLocalizedText.cs.meta
Normal file
11
Assets/Cryville.Common/Unity/UI/TMPLocalizedText.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c03870a7d4386e846be005a0ac36e987
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user