public void StartFadeOnIcon(ConstellationMenuIcon icon,
                                    IconState newState)
        {
            bool hoverChanged = false;

            if (newState == IconState.Hovering)
            {
                if (hoverIcon != null)
                {
                    hoverIcon.FadeIfNeeded(IconState.Hovering,
                                           IconState.Shown);
                }
                hoverIcon    = icon;
                hoverChanged = true;
            }

            if (icon == hoverIcon &&
                newState == IconState.Closed)
            {
                hoverIcon    = null;
                hoverChanged = true;
            }

            if (hoverChanged)
            {
                dummyParent.OnHoverChange(GetHoverIcon());
            }
        }
 private bool IsPointingAwayFromIcon(Vector3 cameraCenter, Vector3 laserEndToCameraNormalized,
                                     ConstellationMenuIcon icon)
 {
     if (icon == null)
     {
         return(true);
     }
     return(icon.GetClosestAngle(cameraCenter, laserEndToCameraNormalized) > closeAngle);
 }
        public bool IsDescendentOf(ConstellationMenuIcon parent)
        {
            ConstellationMenuIcon child = this;

            while (child != null)
            {
                if (child == parent)
                {
                    return(true);
                }
                child = child.parentMenu;
            }
            return(false);
        }
 /// Returns IconRelationship.
 /// AncestorOfRhs if this class is a descendant of relative (or they are the same)
 /// DescendantOfRhs if the opposite is true (or rhsIcon is null)
 /// or UnkownRelationship if neither is true.
 public IconRelationship GetRelationship(ConstellationMenuIcon rhsIcon)
 {
     if (rhsIcon == null || IsDescendentOf(rhsIcon))
     {
         return(IconRelationship.DescendantOfRhs);
     }
     else if (rhsIcon.IsDescendentOf(this))
     {
         return(IconRelationship.AncestorOfRhs);
     }
     else
     {
         return(IconRelationship.UnkownRelationship);
     }
 }
        /// Helper function to create a top level icon.
        /// The root icon does not have any interaction or icon
        /// ShowRootIcon() initializes the root icon and opens the next level of icons.
        private ConstellationMenuIcon ShowRootIcon()
        {
            ConstellationMenuIcon rootIcon = (ConstellationMenuIcon)Instantiate(menuIconPrefab, transform);

            rootIcon.transform.position = menuCenter;
            rootIcon.transform.rotation = menuOrientation;
            rootIcon.Initialize(this, menuTree.tree.Root, MENU_SCALE);
            ConstellationMenuIcon.ShowMenu(this, menuTree.tree.Root, rootIcon, menuOrientation,
                                           MENU_SCALE);
            rootIcon.SetDummy();
            if (OnMenuOpened != null)
            {
                OnMenuOpened.Invoke();
            }
            return(rootIcon);
        }
        /// Recursive call to find the child at the deepest MenuLayer
        public ConstellationMenuIcon GetDeepestIcon()
        {
            ConstellationMenuIcon returnValue = this;

            foreach (var child in childMenus)
            {
                if (child.state == IconState.Closed)
                {
                    continue;
                }
                ConstellationMenuIcon otherIcon = child.GetDeepestIcon();
                if (otherIcon.MenuLayer > returnValue.MenuLayer)
                {
                    returnValue = otherIcon;
                }
            }
            return(returnValue);
        }
        private bool StartFade(IconState nextState)
        {
            if (state == nextState)
            {
                return(false);
            }

            if (nextState == IconState.Closed && childMenus.Count > 0)
            {
                FadeChildren(IconState.Closed);
            }
            state          = nextState;
            fadeInProgress = true;

            if (nextState == IconState.Closed)
            {
                menuRoot.MarkGraphDirty();
            }

            fadeParameters = new FadeParameters(nextState);

            buttonActive = fadeParameters.buttonActive;
            SetColliderSize(Mathf.Min(boxCollider.size.x, fadeParameters.colliderSize));

            menuRoot.StartFadeOnIcon(this, nextState);
            ConstellationMenuIcon hoverIcon = (menuRoot == null) ? null : menuRoot.GetHoverIcon();
            // Change the background based on the relationship between this icon and the hoverIcon
            var relationship = GetRelationship(hoverIcon);

            tooltipAlpha.FadeTo(GetTooltipAlpha(relationship),
                                ANIMATION_DURATION_SECONDS, Time.time);
            iconBgAlpha.FadeTo(GetBackgroundAlpha(relationship),
                               ANIMATION_DURATION_SECONDS,
                               Time.time);
            decorationLabelAlpha.FadeTo(GetDecorationLabelAlpha(relationship),
                                        ANIMATION_DURATION_SECONDS, Time.time);
            iconScale.FadeTo(SHOWN_ICON_SCALE,
                             ANIMATION_DURATION_SECONDS,
                             Time.time);
            iconAlpha.FadeTo(fadeParameters.alpha,
                             ANIMATION_DURATION_SECONDS,
                             Time.time);
            return(true);
        }
        /// Fades out and closes all ConstellationMenuIcon's icons except those between the root and
        /// this node.  Ignores children nodes.
        public void HideAllExceptParentsAndChildren()
        {
            ConstellationMenuIcon menu   = this;
            ConstellationMenuIcon parent = menu.parentMenu;

            while (parent != null)
            {
                foreach (var sibling in parent.childMenus)
                {
                    if (sibling != menu)
                    {
                        sibling.FadeChildren(IconState.Closed);
                        sibling.StartFade(IconState.Hidden);
                    }
                }
                menu   = parent;
                parent = parent.parentMenu;
            }
        }
        public float MenuDepth()
        {
            if (dummyParent == null)
            {
                return(0);
            }
            float hoverDepth = 0;

            if (hoverIcon != null)
            {
                // hovering on leaf node moves the menu deeper as if it had children.
                // This is so hovering has the same results across siblings.
                hoverDepth = (hoverIcon.MenuLayer + 1);
            }
            if (graphDirty)
            {
                deepestIcon = dummyParent.GetDeepestIcon();
                graphDirty  = false;
            }
            return(Mathf.Max(hoverDepth, deepestIcon.MenuLayer));
        }
        /// Called recursively when any icon starts to hover.
        public void OnHoverChange(ConstellationMenuIcon hoverIcon)
        {
            foreach (var child in childMenus)
            {
                child.OnHoverChange(hoverIcon);
            }

            var relationship = GetRelationship(hoverIcon);

            decorationLabelAlpha.FadeTo(GetDecorationLabelAlpha(relationship),
                                        ANIMATION_DURATION_SECONDS, Time.time);
            // Change the background based on the relationship between this icon and the hoverIcon
            iconBgAlpha.FadeTo(GetBackgroundAlpha(relationship),
                               ANIMATION_DURATION_SECONDS, Time.time);

            // Change the tooltip based on the relationship between this icon and the hoverIcon
            tooltipAlpha.FadeTo(GetTooltipAlpha(relationship),
                                ANIMATION_DURATION_SECONDS, Time.time);

            // Set how easy/difficult it is to hover based on this relationship
            hoverDelaySeconds = GetHoverDelay(relationship);
        }
 void Update()
 {
     // Update the menu state if it needs to suddenly open or close
     if (!dummyParent && IsButtonClicked())
     {
         SetMenuLocation();
         if (IsMenuInFOV())
         {
             reticleDistance = laserPointer.defaultReticleDistance;
             laserPointer.defaultReticleDistance = menuDistance * POINTER_DISTANCE_SCALE;
             dummyParent = ShowRootIcon();
         }
     }
     else if ((GvrControllerInput.ClickButtonDown && !selected) ||
              IsPointingAway())
     {
         CloseAll();
     }
     else if (dummyParent && GvrControllerInput.AppButtonUp)
     {
         CloseAll();
     }
 }
        /// Creates and shows a layer of icons below this one.
        /// Returns true if a fade needs to occur.
        public static bool ShowMenu(ConstellationMenuRoot root, AssetTree.Node treeNode, ConstellationMenuIcon parent,
                                    Quaternion orientation, float scale,
                                    IconState initialState = IconState.Shown)
        {
            // Determine how many children are in the sub-menu
            List <AssetTree.Node> childItems = treeNode.children;

            // If this is the end of a menu, invoke the action and return early
            if (childItems.Count == 0)
            {
                root.MakeSelection(parent.menuItem);
                root.CloseAll();
                return(false);
            }
            if (parent.childMenus.Count == childItems.Count)
            {
                // children already exist. just fade them in.
                bool stateChanged = false;
                foreach (ConstellationMenuIcon child in parent.childMenus)
                {
                    if (child.StartFade(initialState))
                    {
                        stateChanged = true;
                    }
                    // Close any children.
                    child.FadeChildren(IconState.Closed);
                }
                return(stateChanged);
            }

            List <Vector3> childPositions;

            float radius;

            if (parent.parentMenu != null)
            {
                radius         = (parent.menuCenter - parent.startPosition).magnitude + ITEM_SPACING;
                childPositions = ArrangeInCircle(childItems.Count, radius,
                                                 parent.angleToRoot - Mathf.PI * .5f,
                                                 parent.angleToRoot + Mathf.PI * .5f,
                                                 ITEM_SPACING);
            }
            else
            {
                // Radius needs to expand when there are more icons
                radius = ITEM_SPACING * Mathf.Max(childItems.Count, MIN_ITEM_SPACE) / (2.0f * Mathf.PI);
                //  add one unused position to item positions
                childPositions = ArrangeInCircle(childItems.Count + 1, radius);
            }
            for (int i = 0; i < childItems.Count; ++i)
            {
                Vector3 posOffset = childPositions[i];
                ConstellationMenuIcon childMenu = (ConstellationMenuIcon)Instantiate(root.menuIconPrefab, root.transform);
                childMenu.transform.position   = parent.menuCenter + (orientation * posOffset);
                childMenu.transform.rotation   = orientation;
                childMenu.transform.localScale = Vector3.one * scale;
                childMenu.Initialize(root, parent, childItems[i], parent.menuCenter, scale, initialState);
                childMenu.angleToRoot = Mathf.Atan2(posOffset[1], posOffset[0]);
            }

            return(true);
        }
        /// Called to make this icon visible and interactable
        public void Initialize(ConstellationMenuRoot root, ConstellationMenuIcon _parentMenu, AssetTree.Node node,
                               Vector3 _menuCenter, float scale, IconState initialState)
        {
            parentMenu          = _parentMenu;
            startPosition       = transform.position;
            startScale          = transform.localScale;
            menuRoot            = root;
            menuNode            = node;
            menuCenter          = _menuCenter;
            savedCameraPosition = _parentMenu.savedCameraPosition;
            savedCameraRotation = _parentMenu.savedCameraRotation;
            menuOrientation     = transform.rotation;
            // Icons are oriented up in world space.
            Vector3    iconToCamera     = savedCameraPosition - transform.position;
            Quaternion rotationToCamera = Quaternion.FromToRotation(-transform.forward, iconToCamera.normalized);

            transform.localRotation = rotationToCamera * transform.localRotation;
            menuScale  = scale;
            background = null;
            state      = IconState.Closed;
            if (node != null)
            {
                // Set foreground icon
                menuItem = (ConstellationMenuItem)node.value;
                spriteRenderer.sprite = menuItem.icon;

                gameObject.name = menuItem.name;
                // Set background icon
                background = new GameObject(name + " Item Background");
                background.transform.parent        = transform.parent;
                background.transform.localPosition = transform.localPosition + transform.forward * BACKGROUND_ICON_ZOFFSET;
                background.transform.localRotation = transform.localRotation;
                background.transform.localScale    = transform.localScale;
                backgroundSpriteRenderer           = background.AddComponent <SpriteRenderer>();

                backgroundSpriteRenderer.sprite = menuRoot.iconBackground;
                if (menuNode.children.Count != 0 &&
                    decorationLabelPrefab != null &&
                    menuRoot.expandableIconDecoration)
                {
                    decorationLabel                = Instantiate(decorationLabelPrefab, background.transform);
                    decorationLabelRenderer        = decorationLabel.GetComponent <SpriteRenderer>();
                    decorationLabelRenderer.sprite = menuRoot.expandableIconDecoration;
                    decorationLabel.SetActive(false);
                }
                menuRoot.MarkGraphDirty();

                float tooltipOffset;
                if (menuItem.tooltipSprite)
                {
                    tooltip = new GameObject(name + " Tooltip Sprite");
                    SpriteRenderer tooltipSpriteRenderer = tooltip.AddComponent <SpriteRenderer>();
                    tooltipSpriteRenderer.sprite = menuItem.tooltipSprite;
                    tooltipRenderer = tooltipSpriteRenderer;
                    tooltip.transform.localScale *= TOOLTIP_SPRITE_SCALE;
                    tooltipOffset = TOOLTIP_SPRITE_OFFSET;
                }
                else
                {
                    tooltip      = Instantiate(tooltipPrefab);
                    tooltip.name = name + " Tooltip Text";
                    tooltip.GetComponent <TextMesh>().text = menuItem.toolTip.Replace('\\', '\n');
                    tooltipRenderer = tooltip.GetComponent <MeshRenderer>();
                    tooltip.transform.localScale = Vector3.one * TOOLTIP_TEXT_SCALE;
                    tooltipOffset = TOOLTIP_TEXT_OFFSET;
                }
                tooltip.transform.SetParent(transform, false);
                tooltip.transform.localPosition = Vector3.up * tooltipOffset;

                tooltip.transform.rotation = transform.rotation;
                SetRendererAlpha(tooltipRenderer, DEFAULT_TOOLTIP_ALPHA);
            }

            parentMenu.childMenus.Add(this);
            lineToParent            = GetComponent <LineRenderer>();
            lineToParent.startColor = Color.clear;
            lineToParent.endColor   = Color.clear;


            UpdateLines();
            SetDecorationLabelAlpha(decorationLabelAlpha.ValueAtTime(Time.time));
            SetBackgroundTransparency(iconBgAlpha.ValueAtTime(Time.time));
            SetRendererAlpha(spriteRenderer, iconAlpha.ValueAtTime(Time.time));

            StartFade(initialState);
            SetColliderSize(0.0f);
        }