// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using UltimateXR.Core.Components; using UltimateXR.Extensions.System.Collections; using UnityEngine; using UnityEngine.UI; #if ULTIMATEXR_UNITY_TMPRO using TMPro; #endif namespace UltimateXR.UI.UnityInputModule.Utils { /// /// /// Component that, added to a UI element, will enable support for left-to-right and right-to-left languages. /// Right-to-left languages not only work by setting text alignment to right, they also require the whole layout to /// be right-to-left. /// /// /// To switch from one to another use the static property . /// /// /// The supported UI components are: /// /// /// (Unity UI) /// Text UI (TextMeshPro) /// (Unity UI) /// (Unity UI) /// (Unity UI) /// fill origin (Unity UI) /// /// public class UxrRightToLeftSupport : UxrComponent { #region Public Types & Data /// /// Sets the global right-to-left setting, changing all components. /// Disabled components, or newly instantiated components, will be aligned correctly too. /// public static bool UseRightToLeft { get => s_useRightToLeft; set { s_useRightToLeft = value; EnabledComponents.ForEach(c => c.SetRightToLeft(value)); } } #endregion #region Unity /// /// Initializes the component. /// protected override void Awake() { base.Awake(); CheckInitialize(); } /// /// Sets the RtoL setting when the component is enabled. /// protected override void OnEnable() { base.OnEnable(); SetRightToLeft(s_useRightToLeft); } #endregion #region Private Methods #if ULTIMATEXR_UNITY_TMPRO /// /// Transforms a TMPro alignment value from LtoR to RtoL. /// /// Alignment to transform /// RtoL value private static TextAlignmentOptions GetRtoLAlignmentTMPro(TextAlignmentOptions alignment) { switch (alignment) { case TextAlignmentOptions.TopRight: return TextAlignmentOptions.TopLeft; case TextAlignmentOptions.Right: return TextAlignmentOptions.Left; case TextAlignmentOptions.BottomRight: return TextAlignmentOptions.BottomLeft; case TextAlignmentOptions.BaselineRight: return TextAlignmentOptions.BaselineLeft; case TextAlignmentOptions.MidlineRight: return TextAlignmentOptions.MidlineLeft; case TextAlignmentOptions.CaplineRight: return TextAlignmentOptions.CaplineLeft; case TextAlignmentOptions.TopLeft: return TextAlignmentOptions.TopRight; case TextAlignmentOptions.Left: return TextAlignmentOptions.Right; case TextAlignmentOptions.BottomLeft: return TextAlignmentOptions.BottomRight; case TextAlignmentOptions.BaselineLeft: return TextAlignmentOptions.BaselineRight; case TextAlignmentOptions.MidlineLeft: return TextAlignmentOptions.MidlineRight; case TextAlignmentOptions.CaplineLeft: return TextAlignmentOptions.CaplineRight; } return alignment; } #endif /// /// Transforms a Unity UI alignment value from LtoR to RtoL. /// /// Alignment to transform /// RtoL value private static TextAnchor GetRtoLAlignment(TextAnchor alignment) { switch (alignment) { case TextAnchor.UpperLeft: return TextAnchor.UpperRight; case TextAnchor.UpperRight: return TextAnchor.UpperLeft; case TextAnchor.MiddleLeft: return TextAnchor.MiddleRight; case TextAnchor.MiddleRight: return TextAnchor.MiddleLeft; case TextAnchor.LowerLeft: return TextAnchor.LowerRight; case TextAnchor.LowerRight: return TextAnchor.LowerLeft; } return alignment; } /// /// Transforms a Unity UI corner value from LtoR to RtoL. /// /// Corner to transform /// RtoL value private static GridLayoutGroup.Corner GetRtoLCorner(GridLayoutGroup.Corner corner) { switch (corner) { case GridLayoutGroup.Corner.UpperLeft: return GridLayoutGroup.Corner.UpperRight; case GridLayoutGroup.Corner.UpperRight: return GridLayoutGroup.Corner.UpperLeft; case GridLayoutGroup.Corner.LowerLeft: return GridLayoutGroup.Corner.LowerRight; case GridLayoutGroup.Corner.LowerRight: return GridLayoutGroup.Corner.LowerLeft; } return corner; } /// /// Transforms a Unity UI fill origin value from LtoR to RtoL. /// /// Fill method used /// fill origin to transform /// RtoL value private static int GetRtoLFillOrigin(Image.FillMethod fillMethod, int fillOrigin) { if (fillMethod == Image.FillMethod.Horizontal) { switch (fillOrigin) { case (int)Image.OriginHorizontal.Left: return (int)Image.OriginHorizontal.Right; case (int)Image.OriginHorizontal.Right: return (int)Image.OriginHorizontal.Left; } } else if (fillMethod == Image.FillMethod.Radial90) { switch (fillOrigin) { case (int)Image.Origin90.BottomLeft: return (int)Image.Origin90.BottomRight; case (int)Image.Origin90.BottomRight: return (int)Image.Origin90.BottomLeft; case (int)Image.Origin90.TopLeft: return (int)Image.Origin90.TopRight; case (int)Image.Origin90.TopRight: return (int)Image.Origin90.TopLeft; } } else if (fillMethod == Image.FillMethod.Radial180) { switch (fillOrigin) { case (int)Image.Origin180.Left: return (int)Image.Origin180.Right; case (int)Image.Origin180.Right: return (int)Image.Origin180.Left; } } else if (fillMethod == Image.FillMethod.Radial360) { switch (fillOrigin) { case (int)Image.Origin360.Left: return (int)Image.Origin360.Right; case (int)Image.Origin360.Right: return (int)Image.Origin360.Left; } } return fillOrigin; } /// /// Gets the component references and stores the initial values. /// private void CheckInitialize() { if (_initialized) { return; } #if ULTIMATEXR_UNITY_TMPRO _textTMPro = GetComponent(); if (_textTMPro != null) { _alignmentTMPro = _textTMPro.alignment; } #endif _text = GetComponent(); if (_text != null) { _textAlignment = _text.alignment; } _horizontalLayout = GetComponent(); if (_horizontalLayout) { _horLayoutAlignment = _horizontalLayout.childAlignment; _horLayoutReversed = _horizontalLayout.reverseArrangement; } _verticalLayout = GetComponent(); if (_verticalLayout) { _verLayoutAlignment = _verticalLayout.childAlignment; } _gridLayout = GetComponent(); if (_gridLayout) { _gridStartCorner = _gridLayout.startCorner; _gridChildAlignment = _gridLayout.childAlignment; } _fillImage = GetComponent(); if (_fillImage != null && _fillImage.type == Image.Type.Filled) { _fillOrigin = _fillImage.fillOrigin; } else { _fillImage = null; } _initialized = true; } /// /// Switches this component to LtoR or RtoL. /// /// Whether to use RtoL (true) or LtoR (false) private void SetRightToLeft(bool useRightToLeft) { CheckInitialize(); #if ULTIMATEXR_UNITY_TMPRO if (_textTMPro != null) { _textTMPro.alignment = useRightToLeft ? GetRtoLAlignmentTMPro(_alignmentTMPro) : _alignmentTMPro; } #endif if (_text != null) { _text.alignment = useRightToLeft ? GetRtoLAlignment(_textAlignment) : _textAlignment; } if (_horizontalLayout != null) { _horizontalLayout.childAlignment = useRightToLeft ? GetRtoLAlignment(_horLayoutAlignment) : _horLayoutAlignment; _horizontalLayout.reverseArrangement = useRightToLeft ? !_horLayoutReversed : _horLayoutReversed; } if (_verticalLayout != null) { _verticalLayout.childAlignment = useRightToLeft ? GetRtoLAlignment(_verLayoutAlignment) : _verLayoutAlignment; } if (_gridLayout != null) { _gridLayout.startCorner = useRightToLeft ? GetRtoLCorner(_gridStartCorner) : _gridStartCorner; _gridLayout.childAlignment = useRightToLeft ? GetRtoLAlignment(_gridChildAlignment) : _gridChildAlignment; } if (_fillImage != null) { _fillImage.fillOrigin = useRightToLeft ? GetRtoLFillOrigin(_fillImage.fillMethod, _fillOrigin) : _fillOrigin; } } #endregion #region Private Types & Data private static bool s_useRightToLeft; private bool _initialized; private Text _text; private TextAnchor _textAlignment; private HorizontalLayoutGroup _horizontalLayout; private TextAnchor _horLayoutAlignment; private bool _horLayoutReversed; private VerticalLayoutGroup _verticalLayout; private TextAnchor _verLayoutAlignment; private GridLayoutGroup _gridLayout; private GridLayoutGroup.Corner _gridStartCorner; private TextAnchor _gridChildAlignment; private Image _fillImage; private int _fillOrigin; #if ULTIMATEXR_UNITY_TMPRO private TextMeshProUGUI _textTMPro; private TextAlignmentOptions _alignmentTMPro; #endif #endregion } }