Example #1
0
        public static List <DrawableTextRun>?Collapse(TextLine textLine, TextCollapsingProperties properties, bool isWordEllipsis)
        {
            if (textLine.TextRuns is not List <DrawableTextRun> textRuns || textRuns.Count == 0)
            {
                return(null);
            }

            var runIndex        = 0;
            var currentWidth    = 0.0;
            var collapsedLength = 0;
            var shapedSymbol    = TextFormatterImpl.CreateSymbol(properties.Symbol, FlowDirection.LeftToRight);

            if (properties.Width < shapedSymbol.GlyphRun.Size.Width)
            {
                //Not enough space to fit in the symbol
                return(new List <DrawableTextRun>(0));
            }

            var availableWidth = properties.Width - shapedSymbol.Size.Width;

            while (runIndex < textRuns.Count)
            {
                var currentRun = textRuns[runIndex];

                switch (currentRun)
                {
                case ShapedTextCharacters shapedRun:
                {
                    currentWidth += shapedRun.Size.Width;

                    if (currentWidth > availableWidth)
                    {
                        if (shapedRun.TryMeasureCharacters(availableWidth, out var measuredLength))
                        {
                            if (isWordEllipsis && measuredLength < textLine.Length)
                            {
                                var currentBreakPosition = 0;

                                var lineBreaker = new LineBreakEnumerator(currentRun.Text);

                                while (currentBreakPosition < measuredLength && lineBreaker.MoveNext())
                                {
                                    var nextBreakPosition = lineBreaker.Current.PositionMeasure;

                                    if (nextBreakPosition == 0)
                                    {
                                        break;
                                    }

                                    if (nextBreakPosition >= measuredLength)
                                    {
                                        break;
                                    }

                                    currentBreakPosition = nextBreakPosition;
                                }

                                measuredLength = currentBreakPosition;
                            }
                        }

                        collapsedLength += measuredLength;

                        var collapsedRuns = new List <DrawableTextRun>(textRuns.Count);

                        if (collapsedLength > 0)
                        {
                            var splitResult = TextFormatterImpl.SplitDrawableRuns(textRuns, collapsedLength);

                            collapsedRuns.AddRange(splitResult.First);
                        }

                        collapsedRuns.Add(shapedSymbol);

                        return(collapsedRuns);
                    }

                    availableWidth -= currentRun.Size.Width;


                    break;
                }

                case { } drawableRun:
                {
                    //The whole run needs to fit into available space
                    if (currentWidth + drawableRun.Size.Width > availableWidth)
                    {
                        var collapsedRuns = new List <DrawableTextRun>(textRuns.Count);

                        if (collapsedLength > 0)
                        {
                            var splitResult = TextFormatterImpl.SplitDrawableRuns(textRuns, collapsedLength);

                            collapsedRuns.AddRange(splitResult.First);
                        }

                        collapsedRuns.Add(shapedSymbol);

                        return(collapsedRuns);
                    }

                    break;
                }
                }

                collapsedLength += currentRun.TextSourceLength;

                runIndex++;
            }

            return(null);
        }
Example #2
0
        public override List <DrawableTextRun>?Collapse(TextLine textLine)
        {
            if (textLine.TextRuns is not List <DrawableTextRun> textRuns || textRuns.Count == 0)
            {
                return(null);
            }

            var runIndex     = 0;
            var currentWidth = 0.0;
            var shapedSymbol = TextFormatterImpl.CreateSymbol(Symbol, FlowDirection.LeftToRight);

            if (Width < shapedSymbol.GlyphRun.Size.Width)
            {
                return(new List <DrawableTextRun>(0));
            }

            // Overview of ellipsis structure
            // Prefix length run | Ellipsis symbol | Post split run growing from the end |
            var availableWidth = Width - shapedSymbol.Size.Width;

            while (runIndex < textRuns.Count)
            {
                var currentRun = textRuns[runIndex];

                switch (currentRun)
                {
                case ShapedTextCharacters shapedRun:
                {
                    currentWidth += currentRun.Size.Width;

                    if (currentWidth > availableWidth)
                    {
                        shapedRun.TryMeasureCharacters(availableWidth, out var measuredLength);

                        var collapsedRuns = new List <DrawableTextRun>(textRuns.Count);

                        if (measuredLength > 0)
                        {
                            List <DrawableTextRun>?preSplitRuns = null;
                            List <DrawableTextRun>?postSplitRuns;

                            if (_prefixLength > 0)
                            {
                                var splitResult = TextFormatterImpl.SplitDrawableRuns(textRuns,
                                                                                      Math.Min(_prefixLength, measuredLength));

                                collapsedRuns.AddRange(splitResult.First);

                                preSplitRuns  = splitResult.First;
                                postSplitRuns = splitResult.Second;
                            }
                            else
                            {
                                postSplitRuns = textRuns;
                            }

                            collapsedRuns.Add(shapedSymbol);

                            if (measuredLength <= _prefixLength || postSplitRuns is null)
                            {
                                return(collapsedRuns);
                            }

                            var availableSuffixWidth = availableWidth;

                            if (preSplitRuns is not null)
                            {
                                foreach (var run in preSplitRuns)
                                {
                                    availableSuffixWidth -= run.Size.Width;
                                }
                            }

                            for (var i = postSplitRuns.Count - 1; i >= 0; i--)
                            {
                                var run = postSplitRuns[i];

                                switch (run)
                                {
                                case ShapedTextCharacters endShapedRun:
                                {
                                    if (endShapedRun.TryMeasureCharactersBackwards(availableSuffixWidth,
                                                                                   out var suffixCount, out var suffixWidth))
                                    {
                                        availableSuffixWidth -= suffixWidth;

                                        if (suffixCount > 0)
                                        {
                                            var splitSuffix =
                                                endShapedRun.Split(run.TextSourceLength - suffixCount);

                                            collapsedRuns.Add(splitSuffix.Second !);
                                        }
                                    }

                                    break;
                                }
                                }
                            }
                        }
                        else
                        {
                            collapsedRuns.Add(shapedSymbol);
                        }

                        return(collapsedRuns);
                    }

                    break;
                }
                }

                availableWidth -= currentRun.Size.Width;

                runIndex++;
            }

            return(null);
        }