< Summary

Class:DCL.Components.UIValue
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/UI/UIShape.cs
Covered lines:4
Uncovered lines:10
Coverable lines:14
Total lines:441
Line coverage:28.5% (4 of 14)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
SetPixels(...)0%2100%
SetPercent(...)0%2100%
UIValue(...)0%2100%
GetScaledValue(...)0%3.073080%

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        {
 026            this.type = Unit.PIXELS;
 027            this.value = value;
 028        }
 29
 30        public void SetPercent(float value)
 31        {
 032            this.type = Unit.PERCENT;
 033            this.value = value;
 034        }
 35
 36        public UIValue(float value, Unit unitType = Unit.PIXELS)
 37        {
 038            this.value = value;
 039            this.type = unitType;
 040        }
 41
 42        public float GetScaledValue(float parentSize)
 43        {
 128444            if (type == Unit.PIXELS)
 116145                return value;
 46
 47            // Prevent division by zero
 12348            if (parentSize <= Mathf.Epsilon)
 049                parentSize = 1;
 50
 12351            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;
 135            public bool visible = true;
 136            public float opacity = 1f;
 137            public string hAlign = "center";
 138            public string vAlign = "center";
 139            public UIValue width = new UIValue(100f);
 140            public UIValue height = new UIValue(50f);
 141            public UIValue positionX = new UIValue(0f);
 142            public UIValue positionY = new UIValue(0f);
 143            public bool isPointerBlocker = true;
 144            public string onClick;
 145
 146            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 147        }
 148
 149        public override string componentName => GetDebugName();
 150        public virtual string referencesContainerPrefabName => "";
 151        public UIReferencesContainer referencesContainer;
 152        public RectTransform childHookRectTransform;
 153
 154        public UIShape parentUIComponent { get; protected set; }
 155
 156        public UIShape() { model = new Model(); }
 157
 158        public override int GetClassId() { return (int) CLASS_ID.UI_IMAGE_SHAPE; }
 159
 160        public string GetDebugName()
 161        {
 162            Model model = (Model) this.model;
 163            if (string.IsNullOrEmpty(model.name))
 164            {
 165                return GetType().Name;
 166            }
 167            else
 168            {
 169                return GetType().Name + " - " + model.name;
 170            }
 171        }
 172
 173        public override IEnumerator ApplyChanges(BaseModel newJson) { return null; }
 174
 175        internal T InstantiateUIGameObject<T>(string prefabPath) where T : UIReferencesContainer
 176        {
 177            Model model = (Model) this.model;
 178            GameObject uiGameObject = null;
 179            bool targetParentExists = !string.IsNullOrEmpty(model.parentComponent) &&
 180                                      scene.disposableComponents.ContainsKey(model.parentComponent);
 181
 182            if (targetParentExists)
 183            {
 184                if (scene.disposableComponents.ContainsKey(model.parentComponent))
 185                {
 186                    parentUIComponent = (scene.disposableComponents[model.parentComponent] as UIShape);
 187                }
 188                else
 189                {
 190                    parentUIComponent = scene.GetSharedComponent<UIScreenSpace>();
 191                }
 192            }
 193            else
 194            {
 195                parentUIComponent = scene.GetSharedComponent<UIScreenSpace>();
 196            }
 197
 198            uiGameObject =
 199                UnityEngine.Object.Instantiate(
 200                    Resources.Load(prefabPath),
 201                    parentUIComponent != null ? parentUIComponent.childHookRectTransform : null) as GameObject;
 202            referencesContainer = uiGameObject.GetComponent<T>();
 203
 204            referencesContainer.rectTransform.SetToMaxStretch();
 205
 206            childHookRectTransform = referencesContainer.childHookRectTransform;
 207
 208            referencesContainer.owner = this;
 209
 210            return referencesContainer as T;
 211        }
 212
 213        public virtual void RefreshAll()
 214        {
 215            RefreshDCLLayoutRecursively(refreshSize: true, refreshAlignmentAndPosition: false);
 216            FixMaxStretchRecursively();
 217            RefreshDCLLayoutRecursively_Internal(refreshSize: false, refreshAlignmentAndPosition: true);
 218        }
 219
 220        public void RefreshDCLLayout(bool refreshSize = true, bool refreshAlignmentAndPosition = true)
 221        {
 222            RectTransform parentRT = referencesContainer.GetComponentInParent<RectTransform>();
 223
 224            if (refreshSize)
 225            {
 226                RefreshDCLSize(parentRT);
 227            }
 228
 229            if (refreshAlignmentAndPosition)
 230            {
 231                // Alignment (Alignment uses size so we should always align AFTER resizing)
 232                RefreshDCLAlignmentAndPosition(parentRT);
 233            }
 234        }
 235
 236        protected virtual void RefreshDCLSize(RectTransform parentTransform = null)
 237        {
 238            if (parentTransform == null)
 239            {
 240                parentTransform = referencesContainer.GetComponentInParent<RectTransform>();
 241            }
 242
 243            Model model = (Model) this.model;
 244
 245            referencesContainer.layoutElementRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal,
 246                model.width.GetScaledValue(parentTransform.rect.width));
 247            referencesContainer.layoutElementRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
 248                model.height.GetScaledValue(parentTransform.rect.height));
 249        }
 250
 251        public void RefreshDCLAlignmentAndPosition(RectTransform parentTransform = null)
 252        {
 253            if (parentTransform == null)
 254            {
 255                parentTransform = referencesContainer.GetComponentInParent<RectTransform>();
 256            }
 257
 258            referencesContainer.layoutElement.ignoreLayout = false;
 259            ConfigureAlignment(referencesContainer.layoutGroup);
 260            Utils.ForceRebuildLayoutImmediate(parentTransform);
 261            referencesContainer.layoutElement.ignoreLayout = true;
 262
 263            Model model = (Model) this.model;
 264            // Reposition
 265            Vector3 position = Vector3.zero;
 266            position.x = model.positionX.GetScaledValue(parentTransform.rect.width);
 267            position.y = model.positionY.GetScaledValue(parentTransform.rect.height);
 268
 269            position = Utils.Sanitize(position);
 270            referencesContainer.layoutElementRT.localPosition += position;
 271        }
 272
 273        public virtual void RefreshDCLLayoutRecursively(bool refreshSize = true,
 274            bool refreshAlignmentAndPosition = true)
 275        {
 276            RefreshDCLLayoutRecursively_Internal(refreshSize, refreshAlignmentAndPosition);
 277        }
 278
 279        public void RefreshDCLLayoutRecursively_Internal(bool refreshSize = true,
 280            bool refreshAlignmentAndPosition = true)
 281        {
 282            UIShape rootParent = GetRootParent();
 283
 284            Assert.IsTrue(rootParent != null, "root parent must never be null");
 285
 286            Utils.InverseTransformChildTraversal<UIReferencesContainer>(
 287                (x) =>
 288                {
 289                    if (x.owner != null)
 290                    {
 291                        x.owner.RefreshDCLLayout(refreshSize, refreshAlignmentAndPosition);
 292                    }
 293                },
 294                rootParent.referencesContainer.transform);
 295        }
 296
 297        public void FixMaxStretchRecursively()
 298        {
 299            UIShape rootParent = GetRootParent();
 300
 301            Assert.IsTrue(rootParent != null, "root parent must never be null");
 302
 303            Utils.InverseTransformChildTraversal<UIReferencesContainer>(
 304                (x) =>
 305                {
 306                    if (x.owner != null)
 307                    {
 308                        x.rectTransform.SetToMaxStretch();
 309                    }
 310                },
 311                rootParent.referencesContainer.transform);
 312        }
 313
 314        protected bool ReparentComponent(RectTransform targetTransform, string targetParent)
 315        {
 316            bool targetParentExists = !string.IsNullOrEmpty(targetParent) &&
 317                                      scene.disposableComponents.ContainsKey(targetParent);
 318
 319            if (targetParentExists && parentUIComponent == scene.disposableComponents[targetParent])
 320            {
 321                return false;
 322            }
 323
 324            if (parentUIComponent != null)
 325            {
 326                UIReferencesContainer[] parents = referencesContainer.GetComponentsInParent<UIReferencesContainer>(true)
 327
 328                foreach (var parent in parents)
 329                {
 330                    if (parent.owner != null)
 331                    {
 332                        parent.owner.OnChildDetached(parentUIComponent, this);
 333                    }
 334                }
 335            }
 336
 337            if (targetParentExists)
 338            {
 339                parentUIComponent = scene.disposableComponents[targetParent] as UIShape;
 340            }
 341            else
 342            {
 343                parentUIComponent = scene.GetSharedComponent<UIScreenSpace>();
 344            }
 345
 346            targetTransform.SetParent(parentUIComponent.childHookRectTransform, false);
 347            return true;
 348        }
 349
 350        public UIShape GetRootParent()
 351        {
 352            UIShape parent = null;
 353
 354            if (parentUIComponent != null && !(parentUIComponent is UIScreenSpace))
 355            {
 356                parent = parentUIComponent.GetRootParent();
 357            }
 358            else
 359            {
 360                parent = this;
 361            }
 362
 363            return parent;
 364        }
 365
 366        protected void ConfigureAlignment(LayoutGroup layout)
 367        {
 368            Model model = (Model) this.model;
 369            switch (model.vAlign)
 370            {
 371                case "top":
 372                    switch (model.hAlign)
 373                    {
 374                        case "left":
 375                            layout.childAlignment = TextAnchor.UpperLeft;
 376                            break;
 377                        case "right":
 378                            layout.childAlignment = TextAnchor.UpperRight;
 379                            break;
 380                        default:
 381                            layout.childAlignment = TextAnchor.UpperCenter;
 382                            break;
 383                    }
 384
 385                    break;
 386                case "bottom":
 387                    switch (model.hAlign)
 388                    {
 389                        case "left":
 390                            layout.childAlignment = TextAnchor.LowerLeft;
 391                            break;
 392                        case "right":
 393                            layout.childAlignment = TextAnchor.LowerRight;
 394                            break;
 395                        default:
 396                            layout.childAlignment = TextAnchor.LowerCenter;
 397                            break;
 398                    }
 399
 400                    break;
 401                default: // center
 402                    switch (model.hAlign)
 403                    {
 404                        case "left":
 405                            layout.childAlignment = TextAnchor.MiddleLeft;
 406                            break;
 407                        case "right":
 408                            layout.childAlignment = TextAnchor.MiddleRight;
 409                            break;
 410                        default:
 411                            layout.childAlignment = TextAnchor.MiddleCenter;
 412                            break;
 413                    }
 414
 415                    break;
 416            }
 417        }
 418
 419        protected void SetComponentDebugName()
 420        {
 421            if (referencesContainer == null || model == null)
 422            {
 423                return;
 424            }
 425
 426            referencesContainer.name = componentName;
 427        }
 428
 429        public override void Dispose()
 430        {
 431            if (childHookRectTransform)
 432                Utils.SafeDestroy(childHookRectTransform.gameObject);
 433
 434            base.Dispose();
 435        }
 436
 437        public virtual void OnChildAttached(UIShape parentComponent, UIShape childComponent) { }
 438
 439        public virtual void OnChildDetached(UIShape parentComponent, UIShape childComponent) { }
 440    }
 441}