Exemplo n.º 1
0
        public static List <VisualElement> AddRichText(string text, IButtonRegistry buttonRegistry, VisualElement root, bool isInsideCodeBlock)
        {
            List <VisualElement>   results   = new List <VisualElement>();
            IEnumerable <RichText> richTexts = ParseRichText(text, isInsideCodeBlock);
            //Parse rich texts to create paragraphs.
            List <List <RichText> > paragraphs = new List <List <RichText> > {
                new List <RichText>()
            };

            foreach (RichText richText in richTexts)
            {
                if (richText.richTextTag.tag == RichTextTag.Tag.button || richText.richTextTag.tag == RichTextTag.Tag.code)
                {
                    paragraphs[paragraphs.Count - 1].Add(richText);
                    continue;
                }

                string[] strings = richText.associatedText.Split('\n');
                for (int i = 0; i < strings.Length; i++)
                {
                    if (i != 0)
                    {
                        paragraphs.Add(new List <RichText>());
                    }
                    //Split paragraph content (already split by tag) into individual words
                    string[] wordSplit = Regex.Split(strings[i], @"(?<=[ -])");                     //Split but keep delimiters attached.
                    foreach (var word in wordSplit)
                    {
                        if (!string.IsNullOrEmpty(word))
                        {
                            paragraphs[paragraphs.Count - 1].Add(new RichText(richText.richTextTag, word));
                        }
                    }
                }
            }

            foreach (List <RichText> paragraph in paragraphs)
            {
                //Add all the paragraphs
                VisualElement rootTemp = root;
                root = AddParagraphContainer(root);
                for (int i = 0; i < paragraph.Count; i++)
                {
                    RichText word = paragraph[i];
                    if (i < paragraph.Count - 1)
                    {
                        //If there are more words
                        RichText nextWord = paragraph[i + 1];
                        string   nextText = nextWord.associatedText;
                        if (Regex.IsMatch(nextText, "^[^a-zA-Z] ?"))
                        {
                            VisualElement inlineGroup = new VisualElement();
                            root.Add(inlineGroup);
                            inlineGroup.AddToClassList("inline-text-group");
                            AddRichTextInternal(word, inlineGroup);
                            AddRichTextInternal(nextWord, inlineGroup);
                            ++i;
                            continue;
                        }
                    }

                    AddRichTextInternal(word, root);

                    //Add all the words and style them.
                    void AddRichTextInternal(RichText richText, VisualElement rootToAddTo)
                    {
                        RichTextTag tag        = richText.richTextTag;
                        TextElement inlineText = null;

                        switch (tag.tag)
                        {
                        case RichTextTag.Tag.none:
                            inlineText = AddInlineText(richText.associatedText, rootToAddTo);
                            break;

                        case RichTextTag.Tag.button:
                            if (buttonRegistry == null)
                            {
                                Debug.LogWarning("There was no ButtonRegistry provided to AddRichText. Button tags will not function.");
                                inlineText = AddInlineButton(() => Debug.LogWarning("There was no ButtonRegistry provided to AddRichText. Button tags will not function."), richText.associatedText, rootToAddTo);
                                break;
                            }
                            if (!buttonRegistry.GetRegisteredButtonAction(tag.stringVariables, out Action action))
                            {
                                return;
                            }
                            inlineText = AddInlineButton(action, richText.associatedText, rootToAddTo);
                            break;

                        case RichTextTag.Tag.code:
                            //Scroll
                            ScrollView    codeScroll       = new ScrollView(ScrollViewMode.Horizontal);
                            VisualElement contentContainer = codeScroll.contentContainer;
                            codeScroll.contentViewport.style.flexDirection = FlexDirection.Column;
                            codeScroll.contentViewport.style.alignItems    = Align.Stretch;
                            codeScroll.AddToClassList("code-scroll");
                            root.Add(codeScroll);

                            contentContainer.ClearClassList();
                            contentContainer.AddToClassList("code-container");
                            VisualElement codeContainer = contentContainer;

                            CSharpHighlighter highlighter = new CSharpHighlighter
                            {
                                AddStyleDefinition = false
                            };
                            // To add code, we first use the CSharpHighlighter to construct rich text for us.
                            string highlit = highlighter.Highlight(richText.associatedText);
                            // After constructing new rich text we pass the text back recursively through this function with the new parent.
                            AddRichText(highlit, buttonRegistry, codeContainer, true);                                     // only parse spans because this is all the CSharpHighlighter parses.
                            //Finalise content container
                            foreach (VisualElement child in codeContainer.Children())
                            {
                                if (child.ClassListContains(paragraphContainerClass))
                                {
                                    child.AddToClassList("code");
                                    if (child.childCount == 1)
                                    {
                                        AddInlineText("", child);                                                //This seems to be required to get layout to function properly.
                                    }
                                }
                            }

                            //Begin Hack
                            FieldInfo m_inheritedStyle = typeof(VisualElement).GetField("inheritedStyle", BindingFlags.NonPublic | BindingFlags.Instance);
                            if (m_inheritedStyle == null)
                            {
                                m_inheritedStyle = typeof(VisualElement).GetField("m_InheritedStylesData", BindingFlags.NonPublic | BindingFlags.Instance);
                            }
                            Type      inheritedStylesData = Type.GetType("UnityEngine.UIElements.StyleSheets.InheritedStylesData,UnityEngine");
                            FieldInfo font     = inheritedStylesData.GetField("font", BindingFlags.Public | BindingFlags.Instance);
                            FieldInfo fontSize = inheritedStylesData.GetField("fontSize", BindingFlags.Public | BindingFlags.Instance);
                            Font      consola  = (Font)EditorGUIUtility.Load("consola");

                            contentContainer.Query <Label>().ForEach(l =>
                            {
                                l.AddToClassList("code");


                                //Hack to regenerate the font size as Rich Text tags are removed from the original calculation.
                                object value      = m_inheritedStyle.GetValue(l);
                                StyleFont fontVar = (StyleFont)font.GetValue(value);
                                fontVar.value     = consola;
                                font.SetValue(value, fontVar);
                                StyleLength fontSizeVar = 12;                                        // = (StyleLength) fontSize.GetValue(value); //This doesn't seem to work properly, hard coded for now.
                                fontSize.SetValue(value, fontSizeVar);
                                m_inheritedStyle.SetValue(l, value);
                                Vector2 measuredTextSize = l.MeasureTextSize(l.text.Replace('>', ' '), 0, VisualElement.MeasureMode.Undefined, 0, VisualElement.MeasureMode.Undefined);
                                l.style.width            = measuredTextSize.x;
                                l.style.height           = measuredTextSize.y;
                            });

                            //Button
                            Button codeCopyButtonButtonContainer = new Button(() =>
                            {
                                EditorGUIUtility.systemCopyBuffer = richText.associatedText;
                                Debug.Log("Copied Code to Clipboard");
                            });
                            codeCopyButtonButtonContainer.ClearClassList();
                            codeCopyButtonButtonContainer.AddToClassList("code-button");
                            codeCopyButtonButtonContainer.StretchToParentSize();
                            codeContainer.Add(codeCopyButtonButtonContainer);

                            break;

                        case RichTextTag.Tag.span:
                            Label spanLabel = new Label
                            {
                                text = richText.associatedText
                            };
                            spanLabel.AddToClassList(tag.stringVariables);
                            rootToAddTo.Add(spanLabel);
                            break;

                        case RichTextTag.Tag.image:
                            throw new NotImplementedException();

                        default:
                            throw new ArgumentOutOfRangeException();
                        }

                        if (inlineText != null)
                        {
                            inlineText.style.unityFontStyleAndWeight = tag.fontStyle;
                            if (tag.size > 0)
                            {
                                inlineText.style.fontSize = tag.size;
                            }
                            if (tag.color != Color.clear)
                            {
                                inlineText.style.color = tag.color;
                            }
                            results.Add(inlineText);
                        }
                    }
                }

                root = rootTemp;
            }

            return(results);

            /*void RichTextDebug(string richText) => Debug.Log(GetRichTextCapableText(richText));
             * string GetRichTextCapableText(string richText) => text.Replace("<", "<<b></b>");*/
        }
Exemplo n.º 2
0
 /// <summary>
 /// Adds VisualElements corresponding to the provided rich text to a root.
 /// </summary>
 /// <param name="text">The rich text to parse</param>
 /// <param name="buttonRegistry">A registry that can be queried for keys if there are any button tags.</param>
 /// <param name="root">Visual Element to append the rich text UI to.</param>
 /// <returns>A list of all immediate children added to the root.</returns>
 public static List <VisualElement> AddRichText(string text, IButtonRegistry buttonRegistry, VisualElement root) => AddRichText(text, buttonRegistry, root, false);