< Summary

Class:DCL.Components.UIShape
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/UI/UIShape.cs
Covered lines:125
Uncovered lines:9
Coverable lines:134
Total lines:441
Line coverage:93.2% (125 of 134)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Model()0%110100%
GetDataFromJSON(...)0%110100%
UIShape()0%110100%
GetClassId()0%2100%
GetDebugName()0%220100%
ApplyChanges(...)0%2100%
InstantiateUIGameObject[T](...)0%6.076087.5%
RefreshAll()0%110100%
RefreshDCLLayout(...)0%330100%
RefreshDCLSize(...)0%2.022083.33%
RefreshDCLAlignmentAndPosition(...)0%22092.31%
RefreshDCLLayoutRecursively(...)0%110100%
RefreshDCLLayoutRecursively_Internal(...)0%110100%
FixMaxStretchRecursively()0%220100%
ReparentComponent(...)0%880100%
GetRootParent()0%330100%
ConfigureAlignment(...)0%13130100%
SetComponentDebugName()0%3.143075%
Dispose()0%220100%
OnChildAttached(...)0%110100%
OnChildDetached(...)0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/UI/UIShape.cs

#LineLine coverage
 1using DCL.Controllers;
 2using DCL.Helpers;
 3using DCL.Models;
 4using System.Collections;
 5using System.Collections.Generic;
 6using UnityEngine;
 7using UnityEngine.Assertions;
 8using UnityEngine.UI;
 9
 10namespace DCL.Components
 11{
 12    [System.Serializable]
 13    public struct UIValue
 14    {
 15        public enum Unit
 16        {
 17            PERCENT,
 18            PIXELS
 19        }
 20
 21        public float value;
 22        public Unit type;
 23
 24        public void SetPixels(float value)
 25        {
 26            this.type = Unit.PIXELS;
 27            this.value = value;
 28        }
 29
 30        public void SetPercent(float value)
 31        {
 32            this.type = Unit.PERCENT;
 33            this.value = value;
 34        }
 35
 36        public UIValue(float value, Unit unitType = Unit.PIXELS)
 37        {
 38            this.value = value;
 39            this.type = unitType;
 40        }
 41
 42        public float GetScaledValue(float parentSize)
 43        {
 44            if (type == Unit.PIXELS)
 45                return value;
 46
 47            // Prevent division by zero
 48            if (parentSize <= Mathf.Epsilon)
 49                parentSize = 1;
 50
 51            return value / 100 * parentSize;
 52        }
 53    }
 54
 55    public class UIShape<ReferencesContainerType, ModelType> : UIShape
 56        where ReferencesContainerType : UIReferencesContainer
 57        where ModelType : UIShape.Model
 58    {
 59        public UIShape() { }
 60
 61        new public ModelType model { get { return base.model as ModelType; } set { base.model = value; } }
 62
 63        new public ReferencesContainerType referencesContainer { get { return base.referencesContainer as ReferencesCont
 64
 65        public override ComponentUpdateHandler CreateUpdateHandler() { return new UIShapeUpdateHandler<ReferencesContain
 66
 67        bool raiseOnAttached;
 68        bool firstApplyChangesCall;
 69
 70        /// <summary>
 71        /// This is called by UIShapeUpdateHandler before calling ApplyChanges.
 72        /// </summary>
 73        public void PreApplyChanges(BaseModel newModel)
 74        {
 75            model = (ModelType) newModel;
 76
 77            raiseOnAttached = false;
 78            firstApplyChangesCall = false;
 79
 80            if (referencesContainer == null)
 81            {
 82                referencesContainer = InstantiateUIGameObject<ReferencesContainerType>(referencesContainerPrefabName);
 83
 84                raiseOnAttached = true;
 85                firstApplyChangesCall = true;
 86            }
 87            else if (ReparentComponent(referencesContainer.rectTransform, model.parentComponent))
 88            {
 89                raiseOnAttached = true;
 90            }
 91        }
 92
 93        public override void RaiseOnAppliedChanges()
 94        {
 95            RefreshDCLLayout();
 96
 97#if UNITY_EDITOR
 98            SetComponentDebugName();
 99#endif
 100
 101            // We hide the component visibility when it's created (first applychanges)
 102            // as it has default values and appears in the middle of the screen
 103            if (firstApplyChangesCall)
 104                referencesContainer.canvasGroup.alpha = 0f;
 105            else
 106                referencesContainer.canvasGroup.alpha = model.visible ? model.opacity : 0f;
 107
 108            referencesContainer.canvasGroup.blocksRaycasts = model.visible && model.isPointerBlocker;
 109
 110            base.RaiseOnAppliedChanges();
 111
 112            if (raiseOnAttached && parentUIComponent != null)
 113            {
 114                UIReferencesContainer[] parents = referencesContainer.GetComponentsInParent<UIReferencesContainer>(true)
 115
 116                for (int i = 0; i < parents.Length; i++)
 117                {
 118                    UIReferencesContainer parent = parents[i];
 119                    if (parent.owner != null)
 120                    {
 121                        parent.owner.OnChildAttached(parentUIComponent, this);
 122                    }
 123                }
 124            }
 125        }
 126    }
 127
 128    public class UIShape : BaseDisposable
 129    {
 130        [System.Serializable]
 131        public class Model : BaseModel
 132        {
 133            public string name;
 134            public string parentComponent;
 602135            public bool visible = true;
 602136            public float opacity = 1f;
 602137            public string hAlign = "center";
 602138            public string vAlign = "center";
 602139            public UIValue width = new UIValue(100f);
 602140            public UIValue height = new UIValue(50f);
 602141            public UIValue positionX = new UIValue(0f);
 602142            public UIValue positionY = new UIValue(0f);
 602143            public bool isPointerBlocker = true;
 144            public string onClick;
 145
 50146            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 147        }
 148
 144149        public override string componentName => GetDebugName();
 0150        public virtual string referencesContainerPrefabName => "";
 151        public UIReferencesContainer referencesContainer;
 152        public RectTransform childHookRectTransform;
 153
 0154        public UIShape parentUIComponent { get; protected set; }
 155
 354156        public UIShape() { model = new Model(); }
 157
 0158        public override int GetClassId() { return (int) CLASS_ID.UI_IMAGE_SHAPE; }
 159
 160        public string GetDebugName()
 161        {
 144162            Model model = (Model) this.model;
 144163            if (string.IsNullOrEmpty(model.name))
 164            {
 137165                return GetType().Name;
 166            }
 167            else
 168            {
 7169                return GetType().Name + " - " + model.name;
 170            }
 171        }
 172
 0173        public override IEnumerator ApplyChanges(BaseModel newJson) { return null; }
 174
 175        internal T InstantiateUIGameObject<T>(string prefabPath) where T : UIReferencesContainer
 176        {
 76177            Model model = (Model) this.model;
 76178            GameObject uiGameObject = null;
 76179            bool targetParentExists = !string.IsNullOrEmpty(model.parentComponent) &&
 180                                      scene.disposableComponents.ContainsKey(model.parentComponent);
 181
 76182            if (targetParentExists)
 183            {
 22184                if (scene.disposableComponents.ContainsKey(model.parentComponent))
 185                {
 22186                    parentUIComponent = (scene.disposableComponents[model.parentComponent] as UIShape);
 22187                }
 188                else
 189                {
 0190                    parentUIComponent = scene.GetSharedComponent<UIScreenSpace>();
 191                }
 0192            }
 193            else
 194            {
 54195                parentUIComponent = scene.GetSharedComponent<UIScreenSpace>();
 196            }
 197
 76198            uiGameObject =
 199                UnityEngine.Object.Instantiate(
 200                    Resources.Load(prefabPath),
 201                    parentUIComponent != null ? parentUIComponent.childHookRectTransform : null) as GameObject;
 76202            referencesContainer = uiGameObject.GetComponent<T>();
 203
 76204            referencesContainer.rectTransform.SetToMaxStretch();
 205
 76206            childHookRectTransform = referencesContainer.childHookRectTransform;
 207
 76208            referencesContainer.owner = this;
 209
 76210            return referencesContainer as T;
 211        }
 212
 213        public virtual void RefreshAll()
 214        {
 91215            RefreshDCLLayoutRecursively(refreshSize: true, refreshAlignmentAndPosition: false);
 91216            FixMaxStretchRecursively();
 91217            RefreshDCLLayoutRecursively_Internal(refreshSize: false, refreshAlignmentAndPosition: true);
 91218        }
 219
 220        public void RefreshDCLLayout(bool refreshSize = true, bool refreshAlignmentAndPosition = true)
 221        {
 500222            RectTransform parentRT = referencesContainer.GetComponentInParent<RectTransform>();
 223
 500224            if (refreshSize)
 225            {
 310226                RefreshDCLSize(parentRT);
 227            }
 228
 500229            if (refreshAlignmentAndPosition)
 230            {
 231                // Alignment (Alignment uses size so we should always align AFTER resizing)
 334232                RefreshDCLAlignmentAndPosition(parentRT);
 233            }
 500234        }
 235
 236        protected virtual void RefreshDCLSize(RectTransform parentTransform = null)
 237        {
 294238            if (parentTransform == null)
 239            {
 0240                parentTransform = referencesContainer.GetComponentInParent<RectTransform>();
 241            }
 242
 294243            Model model = (Model) this.model;
 244
 294245            referencesContainer.layoutElementRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal,
 246                model.width.GetScaledValue(parentTransform.rect.width));
 294247            referencesContainer.layoutElementRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
 248                model.height.GetScaledValue(parentTransform.rect.height));
 294249        }
 250
 251        public void RefreshDCLAlignmentAndPosition(RectTransform parentTransform = null)
 252        {
 334253            if (parentTransform == null)
 254            {
 0255                parentTransform = referencesContainer.GetComponentInParent<RectTransform>();
 256            }
 257
 334258            referencesContainer.layoutElement.ignoreLayout = false;
 334259            ConfigureAlignment(referencesContainer.layoutGroup);
 334260            Utils.ForceRebuildLayoutImmediate(parentTransform);
 334261            referencesContainer.layoutElement.ignoreLayout = true;
 262
 334263            Model model = (Model) this.model;
 264            // Reposition
 334265            Vector3 position = Vector3.zero;
 334266            position.x = model.positionX.GetScaledValue(parentTransform.rect.width);
 334267            position.y = model.positionY.GetScaledValue(parentTransform.rect.height);
 268
 334269            position = Utils.Sanitize(position);
 334270            referencesContainer.layoutElementRT.localPosition += position;
 334271        }
 272
 273        public virtual void RefreshDCLLayoutRecursively(bool refreshSize = true,
 274            bool refreshAlignmentAndPosition = true)
 275        {
 115276            RefreshDCLLayoutRecursively_Internal(refreshSize, refreshAlignmentAndPosition);
 115277        }
 278
 279        public void RefreshDCLLayoutRecursively_Internal(bool refreshSize = true,
 280            bool refreshAlignmentAndPosition = true)
 281        {
 206282            UIShape rootParent = GetRootParent();
 283
 206284            Assert.IsTrue(rootParent != null, "root parent must never be null");
 285
 206286            Utils.InverseTransformChildTraversal<UIReferencesContainer>(
 287                (x) =>
 288                {
 500289                    if (x.owner != null)
 290                    {
 356291                        x.owner.RefreshDCLLayout(refreshSize, refreshAlignmentAndPosition);
 292                    }
 500293                },
 294                rootParent.referencesContainer.transform);
 206295        }
 296
 297        public void FixMaxStretchRecursively()
 298        {
 91299            UIShape rootParent = GetRootParent();
 300
 91301            Assert.IsTrue(rootParent != null, "root parent must never be null");
 302
 91303            Utils.InverseTransformChildTraversal<UIReferencesContainer>(
 304                (x) =>
 305                {
 238306                    if (x.owner != null)
 307                    {
 166308                        x.rectTransform.SetToMaxStretch();
 309                    }
 238310                },
 311                rootParent.referencesContainer.transform);
 91312        }
 313
 314        protected bool ReparentComponent(RectTransform targetTransform, string targetParent)
 315        {
 68316            bool targetParentExists = !string.IsNullOrEmpty(targetParent) &&
 317                                      scene.disposableComponents.ContainsKey(targetParent);
 318
 68319            if (targetParentExists && parentUIComponent == scene.disposableComponents[targetParent])
 320            {
 22321                return false;
 322            }
 323
 46324            if (parentUIComponent != null)
 325            {
 46326                UIReferencesContainer[] parents = referencesContainer.GetComponentsInParent<UIReferencesContainer>(true)
 327
 186328                foreach (var parent in parents)
 329                {
 47330                    if (parent.owner != null)
 331                    {
 47332                        parent.owner.OnChildDetached(parentUIComponent, this);
 333                    }
 334                }
 335            }
 336
 46337            if (targetParentExists)
 338            {
 22339                parentUIComponent = scene.disposableComponents[targetParent] as UIShape;
 22340            }
 341            else
 342            {
 24343                parentUIComponent = scene.GetSharedComponent<UIScreenSpace>();
 344            }
 345
 46346            targetTransform.SetParent(parentUIComponent.childHookRectTransform, false);
 46347            return true;
 348        }
 349
 350        public UIShape GetRootParent()
 351        {
 315352            UIShape parent = null;
 353
 315354            if (parentUIComponent != null && !(parentUIComponent is UIScreenSpace))
 355            {
 18356                parent = parentUIComponent.GetRootParent();
 18357            }
 358            else
 359            {
 297360                parent = this;
 361            }
 362
 315363            return parent;
 364        }
 365
 366        protected void ConfigureAlignment(LayoutGroup layout)
 367        {
 334368            Model model = (Model) this.model;
 334369            switch (model.vAlign)
 370            {
 371                case "top":
 7372                    switch (model.hAlign)
 373                    {
 374                        case "left":
 2375                            layout.childAlignment = TextAnchor.UpperLeft;
 2376                            break;
 377                        case "right":
 2378                            layout.childAlignment = TextAnchor.UpperRight;
 2379                            break;
 380                        default:
 3381                            layout.childAlignment = TextAnchor.UpperCenter;
 3382                            break;
 383                    }
 384
 385                    break;
 386                case "bottom":
 29387                    switch (model.hAlign)
 388                    {
 389                        case "left":
 8390                            layout.childAlignment = TextAnchor.LowerLeft;
 8391                            break;
 392                        case "right":
 19393                            layout.childAlignment = TextAnchor.LowerRight;
 19394                            break;
 395                        default:
 2396                            layout.childAlignment = TextAnchor.LowerCenter;
 2397                            break;
 398                    }
 399
 400                    break;
 401                default: // center
 298402                    switch (model.hAlign)
 403                    {
 404                        case "left":
 2405                            layout.childAlignment = TextAnchor.MiddleLeft;
 2406                            break;
 407                        case "right":
 2408                            layout.childAlignment = TextAnchor.MiddleRight;
 2409                            break;
 410                        default:
 294411                            layout.childAlignment = TextAnchor.MiddleCenter;
 412                            break;
 413                    }
 414
 415                    break;
 416            }
 294417        }
 418
 419        protected void SetComponentDebugName()
 420        {
 144421            if (referencesContainer == null || model == null)
 422            {
 0423                return;
 424            }
 425
 144426            referencesContainer.name = componentName;
 144427        }
 428
 429        public override void Dispose()
 430        {
 83431            if (childHookRectTransform)
 51432                Utils.SafeDestroy(childHookRectTransform.gameObject);
 433
 83434            base.Dispose();
 83435        }
 436
 114437        public virtual void OnChildAttached(UIShape parentComponent, UIShape childComponent) { }
 438
 38439        public virtual void OnChildDetached(UIShape parentComponent, UIShape childComponent) { }
 440    }
 441}