Exemple #1
0
        internal static void RunStartupCode(TutorialProjectSettings projectSettings)
        {
            if (projectSettings.InitialScene != null)
            {
                EditorSceneManager.OpenScene(AssetDatabase.GetAssetPath(projectSettings.InitialScene));
            }

            TutorialManager.WriteAssetsToTutorialDefaultsFolder();

            // Ensure Editor is in predictable state
            EditorPrefs.SetString("ComponentSearchString", string.Empty);
            Tools.current = Tool.Move;

            if (TutorialEditorUtils.FindAssets <TutorialContainer>().Any())
            {
                var existingWindow = EditorWindowUtils.FindOpenInstance <TutorialWindow>();
                if (existingWindow)
                {
                    existingWindow.Close();
                }
                ShowTutorialWindow();
            }

            // NOTE camera settings can be applied successfully only after potential layout changes
            if (projectSettings.InitialCameraSettings != null && projectSettings.InitialCameraSettings.Enabled)
            {
                projectSettings.InitialCameraSettings.Apply();
            }

            if (projectSettings.WelcomePage)
            {
                TutorialModalWindow.Show(projectSettings.WelcomePage);
            }
        }
Exemple #2
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            if (GUILayout.Button(Localization.Tr("Show Welcome Dialog")))
            {
                TutorialModalWindow.TryToShow(Target, null);
            }

            if (k_IsAuthoringMode)
            {
                GUILayout.Space(10);
                //base.OnInspectorGUI();
                DrawPropertiesExcluding(serializedObject, k_PropsToIgnore);
            }

            bool eventOffOrRuntimeOnlyExists = false;

            for (int i = 0; i < m_Buttons.arraySize; i++)
            {
                m_CurrentEvent = m_Buttons.GetArrayElementAtIndex(i).FindPropertyRelative(k_OnClickEventPropertyPath);
                if (!TutorialEditorUtils.EventIsNotInState(m_CurrentEvent, UnityEngine.Events.UnityEventCallState.EditorAndRuntime))
                {
                    continue;
                }

                eventOffOrRuntimeOnlyExists = true;
                break;
            }
            if (eventOffOrRuntimeOnlyExists)
            {
                TutorialEditorUtils.RenderEventStateWarning();
            }
            serializedObject.ApplyModifiedProperties();
        }
Exemple #3
0
        /// <summary>
        /// Shows Tutorials window using the currently specified behaviour.
        /// </summary>
        /// <remarks>
        /// Different behaviors:
        /// 1. If a single root tutorial container (TutorialContainer.ParentContainer is null) that has Project Layout specified exists,
        ///    the window is loaded and shown using the specified project window layout (old behaviour).
        ///    If the project layout does not contain Tutorials window, the window is shown an as a free-floating window.
        /// 2. If no root tutorial containers exist, or a root container's Project Layout is not specified, the window is shown
        ///     by anchoring and docking it next to the Inspector (new behaviour). If the Inspector is not available,
        ///     the window is shown an as a free-floating window.
        /// 3. If there is more than one root tutorial container with different Project Layout setting in the project,
        ///    one asset is chosen randomly to specify the behavior.
        /// 4. If Tutorials window is already created, it is simply brought to the foreground and focused.
        /// </remarks>
        /// <returns>The the created, or aleady existing, window instance.</returns>
        public static TutorialWindow ShowTutorialWindow()
        {
            var rootContainers = TutorialEditorUtils.FindAssets <TutorialContainer>()
                                 .Where(container => container.ParentContainer is null);
            var defaultContainer = rootContainers.FirstOrDefault();
            var projectLayout    = defaultContainer?.ProjectLayout;

            if (rootContainers.Any(container => container.ProjectLayout != projectLayout))
            {
                Debug.LogWarningFormat(
                    "There is more than one TutorialContainers asset with different Project Layout setting in the project. " +
                    "Using asset at path {0} for the window behavior settings.",
                    AssetDatabase.GetAssetPath(defaultContainer)
                    );
            }

            TutorialWindow window = null;

            if (!rootContainers.Any() || defaultContainer.ProjectLayout == null)
            {
                window = TutorialWindow.GetOrCreateWindowNextToInspector();
            }
            else if (defaultContainer.ProjectLayout != null)
            {
                window = TutorialWindow.GetOrCreateWindowAndLoadLayout(defaultContainer);
            }

            // If we have more than one root container, we show a selection view. Exactly one (or zero) container
            // is set active immediately without possibility to return to the the selection view.
            if (rootContainers.Count() > 1)
            {
                window.SetContainers(rootContainers);
            }
            else
            {
                window.ActiveContainer = defaultContainer;
            }

            return(window);
        }
        /// <summary>
        /// Shows Tutorials window using the currently specified behaviour.
        /// </summary>
        /// <remarks>
        /// Different behaviors:
        /// 1. If a single TutorialContainer asset that has TutorialContainer.ProjectLayout specified exists,
        ///    the window is loaded and shown using the specified project window layout (old behaviour).
        ///    If the project layout does not contain Tutorials window, the window is shown an as free-floating window.
        /// 2. If no TutorialContainer assets exist, or TutorialContainer.ProjectLayout is not specified, the window is shown
        ///     by anchoring and docking it next to the Inspector (new behaviour). If the Inspector is not available,
        ///     the window is shown an as free-floating window.
        /// 3. If there is more than one TutorialContainer asset with different Project Layout setting in the project,
        ///    one asset is chosen randomly to specify the behavior.
        /// 4. If Tutorials window is already created, it is simply brought to the foreground and focused.
        /// </remarks>
        /// <returns>The the created, or aleady existing, window instance.</returns>
        public static TutorialWindow ShowTutorialWindow()
        {
            var containers       = TutorialEditorUtils.FindAssets <TutorialContainer>();
            var defaultContainer = containers.FirstOrDefault();
            var projectLayout    = defaultContainer?.ProjectLayout;

            if (containers.Any(container => container.ProjectLayout != projectLayout))
            {
                Debug.LogWarningFormat(
                    "There is more than one TutorialContainers asset with different Project Layout setting in the project. " +
                    "Using asset at path {0} for the window behavior settings.",
                    AssetDatabase.GetAssetPath(defaultContainer)
                    );
            }

            TutorialWindow window = null;

            if (!containers.Any() || defaultContainer.ProjectLayout == null)
            {
                window = TutorialWindow.CreateNextToInspector();
            }
            else if (defaultContainer.ProjectLayout != null)
            {
                window = TutorialWindow.CreateWindowAndLoadLayout(defaultContainer);
            }

            window.SetContainers(containers);

            // If we have only one tutorial container, we set it active immediately
            if (containers.Count() == 1)
            {
                window.ActiveContainer = defaultContainer;
            }

            return(window);
        }
 /// <summary>
 /// Opens the URL Of the section, if any
 /// </summary>
 public void OpenUrl()
 {
     // TODO by making a static OpenUrl(string url) utility function we can easily track rich text hyperlink clicks also
     TutorialEditorUtils.OpenUrl(Url);
     AnalyticsHelper.SendExternalReferenceEvent(Url, Heading.Untranslated, Metadata, Tutorial?.LessonId);
 }
        /// <summary>
        /// Transforms HTML tags to word element labels with different styles to enable rich text.
        /// </summary>
        /// <param name="htmlText"></param>
        /// <param name="targetContainer">
        /// The following need to set for the container's style:
        /// flex-direction: row;
        /// flex-wrap: wrap;
        /// </param>
        /// <returns>List of VisualElements made from the parsed text.</returns>
        public static List <VisualElement> RichTextToVisualElements(string htmlText, VisualElement targetContainer)
        {
            bool   addError  = false;
            string errorText = "";

            try
            {
                XDocument.Parse("<content>" + htmlText + "</content>");
            }
            catch (Exception e)
            {
                targetContainer.Clear();
                errorText = e.Message;
                htmlText  = ShowContentWithError(htmlText);
                addError  = true;
            }
            List <VisualElement> elements = new List <VisualElement>();

            targetContainer.Clear();
            bool   boldOn          = false; // <b> sets this on </b> sets off
            bool   italicOn        = false; // <i> </i>
            bool   forceWordWrap   = false;
            bool   linkOn          = false;
            string linkURL         = "";
            bool   firstLine       = true;
            bool   lastLineHadText = false;

            // start streaming text per word to elements while retaining current style for each word block
            string[] lines = htmlText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);

            foreach (string line in lines)
            {
                // Check if the line begins with whitespace and turn that into corresponding Label
                string initialWhiteSpaces = "";
                foreach (char singleCharacter in line)
                {
                    if (singleCharacter == ' ' || singleCharacter == '\t')
                    {
                        initialWhiteSpaces += singleCharacter;
                    }
                    else
                    {
                        break;
                    }
                }

                string processedLine = PreProcessRichText(line);

                // Separate the line into words
                string[] words = processedLine.Split(new[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries);

                if (!lastLineHadText)
                {
                    if (!firstLine)
                    {
                        elements.Add(AddParagraphToElement(targetContainer));
                    }

                    if (initialWhiteSpaces.Length > 0)
                    {
                        WhiteSpaceLabel indentationLabel = new WhiteSpaceLabel(initialWhiteSpaces);
                        targetContainer.Add(indentationLabel);
                        elements.Add(indentationLabel);
                    }
                }

                if (!firstLine && lastLineHadText)
                {
                    elements.Add(AddLinebreakToElement(targetContainer));
                    lastLineHadText = false;
                    if (initialWhiteSpaces.Length > 0)
                    {
                        WhiteSpaceLabel indentationLabel = new WhiteSpaceLabel(initialWhiteSpaces);
                        targetContainer.Add(indentationLabel);
                        elements.Add(indentationLabel);
                    }
                }

                foreach (string word in words)
                {
                    // Wrap every character instead of word in case of Chinese and Japanese
                    // Note: override with <wordwrap>Force word wrapping here</wordwrap>

                    if (word == "" || word == " " || word == "   ")
                    {
                        continue;
                    }
                    lastLineHadText = true;
                    string strippedWord   = word;
                    bool   removeBold     = false;
                    bool   removeItalic   = false;
                    bool   addParagraph   = false;
                    bool   removeLink     = false;
                    bool   removeWordWrap = false;

                    strippedWord = strippedWord.Trim();

                    if (strippedWord.Contains("<b>"))
                    {
                        strippedWord = strippedWord.Replace("<b>", "");
                        boldOn       = true;
                    }
                    if (strippedWord.Contains("<i>"))
                    {
                        strippedWord = strippedWord.Replace("<i>", "");
                        italicOn     = true;
                    }
                    if (strippedWord.Contains("<wordwrap>"))
                    {
                        strippedWord  = strippedWord.Replace("<wordwrap>", "");
                        forceWordWrap = true;
                    }
                    if (strippedWord.Contains("<a"))
                    {
                        strippedWord = strippedWord.Replace("<a", "");
                        linkOn       = true;
                    }
                    bool wrapCharacters = !forceWordWrap && NeedSymbolWrapping(word);
                    if (linkOn && strippedWord.Contains("href="))
                    {
                        strippedWord = strippedWord.Replace("href=", "");
                        int linkFrom = strippedWord.IndexOf("\"", StringComparison.Ordinal) + 1;
                        int linkTo   = strippedWord.LastIndexOf("\"", StringComparison.Ordinal);
                        linkURL      = strippedWord.Substring(linkFrom, linkTo - linkFrom);
                        strippedWord = strippedWord.Substring(linkTo + 2, (strippedWord.Length - 2) - linkTo);
                        strippedWord.Replace("\">", "");
                    }

                    if (strippedWord.Contains("</a>"))
                    {
                        strippedWord = strippedWord.Replace("</a>", "");
                        removeLink   = true;
                    }
                    if (strippedWord.Contains("<br/>"))
                    {
                        strippedWord = strippedWord.Replace("<br/>", "");
                        addParagraph = true;
                    }
                    if (strippedWord.Contains("</b>"))
                    {
                        strippedWord = strippedWord.Replace("</b>", "");
                        removeBold   = true;
                    }
                    if (strippedWord.Contains("</i>"))
                    {
                        strippedWord = strippedWord.Replace("</i>", "");
                        removeItalic = true;
                    }
                    if (strippedWord.Contains("</wordwrap>"))
                    {
                        strippedWord   = strippedWord.Replace("</wordwrap>", "");
                        removeWordWrap = true;
                    }
                    if (boldOn && strippedWord != "")
                    {
                        if (wrapCharacters)
                        {
                            foreach (char character in strippedWord)
                            {
                                AddLabel <BoldLabel>(character.ToString(), elements, targetContainer);
                            }
                        }
                        else
                        {
                            AddLabel <BoldLabel>(strippedWord, elements, targetContainer);
                        }
                    }
                    else if (italicOn && strippedWord != "")
                    {
                        if (wrapCharacters)
                        {
                            foreach (char character in strippedWord)
                            {
                                AddLabel <ItalicLabel>(character.ToString(), elements, targetContainer);
                            }
                        }
                        else
                        {
                            AddLabel <ItalicLabel>(strippedWord, elements, targetContainer);
                        }
                    }
                    else if (addParagraph)
                    {
                        elements.Add(AddParagraphToElement(targetContainer));
                    }
                    else if (linkOn && !string.IsNullOrEmpty(linkURL))
                    {
                        var label = new HyperlinkLabel
                        {
                            text    = strippedWord,
                            tooltip = linkURL
                        };
                        label.RegisterCallback <MouseUpEvent, string>(
                            (evt, linkurl) =>
                        {
                            TutorialEditorUtils.OpenUrl(linkurl);
                        },
                            linkURL
                            );

                        targetContainer.Add(label);
                        elements.Add(label);
                    }
                    else
                    {
                        if (strippedWord != "")
                        {
                            if (wrapCharacters)
                            {
                                foreach (char character in strippedWord)
                                {
                                    AddLabel <TextLabel>(character.ToString(), elements, targetContainer);
                                }
                            }
                            else
                            {
                                AddLabel <TextLabel>(strippedWord, elements, targetContainer);
                            }
                        }
                    }

                    if (removeBold)
                    {
                        boldOn = false;
                    }
                    if (removeItalic)
                    {
                        italicOn = false;
                    }
                    if (removeLink)
                    {
                        linkOn  = false;
                        linkURL = "";
                    }
                    if (removeWordWrap)
                    {
                        forceWordWrap = false;
                    }
                }
                firstLine = false;
            }

            if (addError)
            {
                var label = new ParseErrorLabel()
                {
                    text    = Localization.Tr("PARSE ERROR"),
                    tooltip = Localization.Tr("Click here to see more information in the console.")
                };
                label.RegisterCallback <MouseUpEvent>((e) => Debug.LogError(errorText));
                targetContainer.Add(label);
                elements.Add(label);
            }
            return(elements);
        }
 /// <summary>
 /// Opens the URL Of the section, if any
 /// </summary>
 public void OpenUrl()
 {
     TutorialEditorUtils.OpenUrl(Url);
     AnalyticsHelper.SendExternalReferenceEvent(Url, Heading.Untranslated, Metadata, Tutorial?.LessonId);
 }