internal static float ZeroLinesFit(ICharSequence text, TextPaint paint, float min, float max, int availWidth, int availHeight)
        {
            if (availHeight > int.MaxValue / 3)
            {
                return(max);
            }
            if (availWidth > int.MaxValue / 3)
            {
                var fontMetrics     = paint.GetFontMetrics();
                var fontLineHeight  = fontMetrics.Descent * FontScale - fontMetrics.Ascent * FontScale;
                var fontPixelSize   = paint.TextSize * FontScale;
                var lineHeightRatio = fontLineHeight / fontPixelSize;

                var result = (availHeight / lineHeightRatio - 0.1f);
                return(System.Math.Min(result, max));
            }

            if (max - min < Precision)
            {
                return(min);
            }

            float mid = (max + min) / 2.0f;

            paint.TextSize = mid * Scale;
            var layout    = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);
            var lineCount = layout.LineCount;
            var height    = layout.Height - layout.BottomPadding + layout.TopPadding;

            if (height > availHeight)
            {
                return(ZeroLinesFit(text, paint, min, mid, availWidth, availHeight));
            }
            if (height < availHeight)
            {
                return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight));
            }
            float maxLineWidth = 0;

            for (int i = 0; i < lineCount; i++)
            {
                if (layout.GetLineWidth(i) > maxLineWidth)
                {
                    maxLineWidth = layout.GetLineWidth(i);
                }
            }
            if (maxLineWidth > availWidth)
            {
                return(ZeroLinesFit(text, paint, min, mid, availWidth, availHeight));
            }
            if (maxLineWidth < availWidth)
            {
                return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight));
            }
            return(mid);
        }
#pragma warning disable IDE0060 // Remove unused parameter
        static float DescendingWidthFit(ICharSequence text, TextPaint paint, int lines, float min, float max, int availWidth, int availHeight, float step)
#pragma warning restore IDE0060 // Remove unused parameter
        {
            float result;

            for (result = max; result > min; result -= step)
            {
                paint.TextSize = result * Scale * FontScale;
                var layout = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);
                if (layout.LineCount <= lines)
                {
                    return(result);
                }
            }
            return(result);
        }
        static string EndTruncatedIter(string text, TextPaint paint, int secondToLastEnd, int start, int endLow, int endHigh, float availWidth)
        {
            if (endHigh - endLow <= 1)
            {
                return((secondToLastEnd > 0 ? text.Substring(0, secondToLastEnd).TrimEnd() + "\n" : "") + text.Substring(start, endLow - start) + "…");
            }
            int mid          = (endLow + endHigh) / 2;
            var lastLineText = new Java.Lang.String(text.Substring(start, mid - start) + "…");
            var layout       = TextExtensions.StaticLayout(lastLineText, paint, int.MaxValue - 10000, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);

            if (layout.GetLineWidth(0) > availWidth)
            {
                return(EndTruncatedIter(text, paint, secondToLastEnd, start, endLow, mid, availWidth));
            }
            return(EndTruncatedIter(text, paint, secondToLastEnd, start, mid, endHigh, availWidth));
        }
        static ICharSequence EndTruncatedFormattedIter(F9PFormattedString baseFormattedString, TextPaint paint, int secondToLastEnd, int start, int endLow, int endHigh, float availWidth)
        {
            if (endHigh - endLow <= 1)
            {
                return(baseFormattedString.ToSpannableString(EllipsePlacement.End, secondToLastEnd, start, endLow));
            }
            int mid           = (endLow + endHigh) / 2;
            var formattedText = baseFormattedString.ToSpannableString(EllipsePlacement.End, 0, start, mid);
            var layout        = TextExtensions.StaticLayout(formattedText, paint, int.MaxValue - 10000, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);

            if (layout.GetLineWidth(0) > availWidth)
            {
                return(EndTruncatedFormattedIter(baseFormattedString, paint, secondToLastEnd, start, endLow, mid, availWidth));
            }
            return(EndTruncatedFormattedIter(baseFormattedString, paint, secondToLastEnd, start, mid, endHigh, availWidth));
        }
Esempio n. 5
0
        static string MidTruncatedIter(string text, TextPaint paint, int secondToLastEnd, int startLastVisible, int midLastVisible, int startLow, int startHigh, int end, float availWidth, float lineHeightMultiplier)
        {
            if (startHigh - startLow <= 1)
            {
                return((secondToLastEnd > 0 ? text.Substring(0, secondToLastEnd).TrimEnd() + "\n" : "") + text.Substring(startLastVisible, midLastVisible - startLastVisible).TrimEnd() + "…" + text.Substring(startHigh, end - startHigh).TrimStart());
            }
            int mid          = (startLow + startHigh) / 2;
            var lastLineText = new Java.Lang.String(text.Substring(startLastVisible, midLastVisible - startLastVisible).TrimEnd() + "…" + text.Substring(mid, end - mid).TrimStart());

            using (var layout = TextExtensions.StaticLayout(lastLineText, paint, int.MaxValue - 10000, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 0.0f, true))
            {
                if (layout.GetLineWidth(0) > availWidth)
                {
                    return(MidTruncatedIter(text, paint, secondToLastEnd, startLastVisible, midLastVisible, mid, startHigh, end, availWidth, lineHeightMultiplier));
                }
                return(MidTruncatedIter(text, paint, secondToLastEnd, startLastVisible, midLastVisible, startLow, mid, end, availWidth, lineHeightMultiplier));
            }
        }
Esempio n. 6
0
        static ICharSequence MidTruncatedFormattedIter(F9PFormattedString baseFormattedString, TextPaint paint, int secondToLastEnd, int startLastVisible, int midLastVisible, int startLow, int startHigh, int end, float availWidth, float lineHeightMultiplier)
        {
            if (startHigh - startLow <= 1)
            {
                return(baseFormattedString.ToSpannableString(EllipsePlacement.Mid, secondToLastEnd, startHigh, end, startLastVisible, midLastVisible));
            }
            int mid           = (startLow + startHigh) / 2;
            var formattedText = baseFormattedString.ToSpannableString(EllipsePlacement.Mid, 0, mid, end, startLastVisible, midLastVisible);

            using (var layout = TextExtensions.StaticLayout(formattedText, paint, int.MaxValue - 10000, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 0.0f, true))
            {
                if (layout.GetLineWidth(0) > availWidth)
                {
                    return(MidTruncatedFormattedIter(baseFormattedString, paint, secondToLastEnd, startLastVisible, midLastVisible, mid, startHigh, end, availWidth, lineHeightMultiplier));
                }
                return(MidTruncatedFormattedIter(baseFormattedString, paint, secondToLastEnd, startLastVisible, midLastVisible, startLow, mid, end, availWidth, lineHeightMultiplier));
            }
        }
Esempio n. 7
0
        SizeRequest InternalLayout(F9PTextView control, TextControlState state)
        {
            if (Element is Forms9Patch.Label element && control != null)
            {
                ICharSequence text        = state.JavaText;
                var           tmpFontSize = BoundTextSize(element.FontSize);
                control.Typeface = state.Typeface;
                //control.SetTextColor(state.TextColor.ToAndroid());
                UpdateColor(control);
                control.TextSize = tmpFontSize;

                control.IsNativeDrawEnabled = false;
                control.SetSingleLine(false);
                control.SetMaxLines(int.MaxValue / 2);
                control.SetIncludeFontPadding(false);
                control.Ellipsize = null;

                double tmpHt = -1;
                double tmpWd = -1;

                var fontMetrics    = control.Paint.GetFontMetrics();
                var fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent;
                var fontLeading    = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent);

                if (state.Lines == 0)
                {
                    if (state.AvailHeight < int.MaxValue / 3)
                    {
                        tmpFontSize = TextPaintExtensions.ZeroLinesFit(state.JavaText, new TextPaint(control.Paint), ModelMinFontSize, tmpFontSize, state.AvailWidth, state.AvailHeight);
                    }
                }
                else
                {
                    if (state.AutoFit == AutoFit.Lines)
                    {
                        if (state.AvailHeight > int.MaxValue / 3)
                        {
                            tmpHt = System.Math.Round(state.Lines * fontLineHeight + (state.Lines - 1) * fontLeading);
                        }
                        else
                        {
                            var fontPointSize   = tmpFontSize;
                            var lineHeightRatio = fontLineHeight / fontPointSize;
                            var leadingRatio    = fontLeading / fontPointSize;
                            tmpFontSize = ((state.AvailHeight / (state.Lines + leadingRatio * (state.Lines - 1))) / lineHeightRatio - 0.1f);
                        }
                    }
                    else if (state.AutoFit == AutoFit.Width)
                    {
                        tmpFontSize = TextPaintExtensions.WidthFit(state.JavaText, new TextPaint(control.Paint), state.Lines, ModelMinFontSize, tmpFontSize, state.AvailWidth, state.AvailHeight);
                    }
                }

                tmpFontSize = BoundTextSize(tmpFontSize);

                // this is the optimal font size.  Let it be known!
                if (System.Math.Abs(tmpFontSize - element.FittedFontSize) > 0.1)
                {
                    if (System.Math.Abs(tmpFontSize - element.FontSize) < 0.1 || (element.FontSize < 0 && System.Math.Abs(tmpFontSize - F9PTextView.DefaultTextSize) < 0.1))
                    {
                        element.FittedFontSize = -1;
                    }
                    else
                    {
                        element.FittedFontSize = tmpFontSize;
                    }
                }

                var syncFontSize = (float)((ILabel)element).SynchronizedFontSize;
                if (syncFontSize >= 0 && System.Math.Abs(tmpFontSize - syncFontSize) > 0.1)
                {
                    tmpFontSize = syncFontSize;
                }

                control.TextSize       = tmpFontSize;
                state.RenderedFontSize = tmpFontSize;
                var layout = TextExtensions.StaticLayout(state.JavaText, new TextPaint(control.Paint), state.AvailWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);

                int lines = state.Lines;
                if (lines == 0 && state.AutoFit == AutoFit.None)
                {
                    for (int i = 0; i < layout.LineCount; i++)
                    {
                        if (layout.GetLineBottom(i) <= state.AvailHeight - layout.TopPadding - layout.BottomPadding)
                        {
                            lines++;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                if (layout.Height > state.AvailHeight || (lines > 0 && layout.LineCount > lines))
                {
                    if (state.Lines == 1)
                    {
                        control.SetSingleLine(true);
                        control.SetMaxLines(1);
                        control.Ellipsize = state.LineBreakMode.ToEllipsize();
                    }
                    else
                    {
                        layout = TextPaintExtensions.Truncate(state.Text, element.F9PFormattedString, new TextPaint(control.Paint), state.AvailWidth, state.AvailHeight, element.AutoFit, element.LineBreakMode, ref lines, ref text);
                    }
                }
                lines = lines > 0 ? System.Math.Min(lines, layout.LineCount) : layout.LineCount;

                for (int i = 0; i < lines; i++)
                {
                    tmpHt = layout.GetLineBottom(i);
                    var width = layout.GetLineWidth(i);
                    if (width > tmpWd)
                    {
                        tmpWd = System.Math.Ceiling(width);
                    }
                }
                if (state.AutoFit == AutoFit.None && state.Lines > 0)
                {
                    control.SetMaxLines(state.Lines);
                }

                if (element.IsDynamicallySized && state.Lines > 0 && state.AutoFit == AutoFit.Lines)
                {
                    fontMetrics    = control.Paint.GetFontMetrics();
                    fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent;
                    fontLeading    = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent);
                    tmpHt          = fontLineHeight * state.Lines + fontLeading * (state.Lines - 1);
                }

                control.Gravity = element.HorizontalTextAlignment.ToHorizontalGravityFlags() | element.VerticalTextAlignment.ToVerticalGravityFlags();

                if (element.Text != null)
                {
                    control.Text = text.ToString();
                }
                else
                {
                    control.TextFormatted = text;
                }

                var result = new SizeRequest(new Size(System.Math.Ceiling(tmpWd), System.Math.Ceiling(tmpHt)), new Size(10, System.Math.Ceiling(tmpHt)));

                if (element.LineBreakMode == LineBreakMode.NoWrap)
                {
                    control.SetSingleLine(true);
                }

                control.IsNativeDrawEnabled = true;
                if (control == Control)
                {
                    //P42.Utils.Debug.Message(Element?.HtmlText, "!!!~~~~~~~ REQUEST LAYOUT~~~~~~~~~!!!");
                    // none of the below seems to help the issue where the label is not apparing in ConnectionCalc cells
                    //Control.RequestLayout();
                    ////P42.Utils.Debug.Message(Element?.HtmlText, "Control.Invalidate()");
                    //Control.Invalidate();
                    //Invalidate();
                    //var widthSpec = MeasureSpec.MakeMeasureSpec(tmpWd, Android.Views.MeasureSpecMode.Exactly);
                    //var heightSpec = MeasureSpec.MakeMeasureSpec(tmpHt, Android.Views.MeasureSpecMode.Exactly);
                    //Control.Measure(widthSpec, heightSpec);
                    //Control.RequestLayout();
                    //Control.Layout(0, 0, (int)System.Math.Ceiling(tmpWd), (int)System.Math.Ceiling(tmpHt));
                    //Control
                }
                return(result);
            }
            return(new SizeRequest(Size.Zero));
        }
#pragma warning disable IDE0060 // Remove unused parameter
        internal static StaticLayout Truncate(string text, Forms9Patch.F9PFormattedString baseFormattedString, TextPaint paint, int availWidth, int availHeight, AutoFit fit, LineBreakMode lineBreakMode, ref int lines, ref ICharSequence textFormatted)
#pragma warning restore IDE0060 // Remove unused parameter
        {
            StaticLayout layout;
            var          fontMetrics    = paint.GetFontMetrics();
            var          fontLineHeight = fontMetrics.Descent - fontMetrics.Ascent;
            var          fontLeading    = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent);

            textFormatted = ((ICharSequence)baseFormattedString?.ToSpannableString()) ?? new Java.Lang.String(text);
            if (lines > 0)
            {
                if (baseFormattedString != null)
                {
                    layout = TextExtensions.StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);

                    if (layout.Height > availHeight)
                    {
                        var visibleLines = (int)((fontLeading + availHeight) / (fontLineHeight + fontLeading));
                        if (visibleLines < lines)
                        {
                            lines = visibleLines;
                        }
                    }
                    if (layout.LineCount > lines && lines > 0)
                    {
                        var secondToLastEnd = lines > 1 ? layout.GetLineEnd(lines - 2) : 0;
                        var start           = lines > 1 ? layout.GetLineStart(layout.LineCount - 2) : 0;
                        switch (lineBreakMode)
                        {
                        case LineBreakMode.HeadTruncation:
                            textFormatted = StartTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;

                        case LineBreakMode.MiddleTruncation:
                            textFormatted = MidTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), (layout.GetLineEnd(lines - 1) + layout.GetLineStart(lines - 1)) / 2 - 1, start, layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;

                        case LineBreakMode.TailTruncation:
                            textFormatted = EndTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;

                        default:
                            textFormatted = TruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;
                        }
                    }
                }
                else
                {
                    layout = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);
                    if (layout.Height > availHeight)
                    {
                        var visibleLines = (int)((fontLeading + availHeight) / (fontLineHeight + fontLeading));
                        if (visibleLines < lines)
                        {
                            lines = visibleLines;
                        }
                    }
                    if (layout.LineCount > lines && lines > 0)
                    {
                        var secondToLastEnd = lines > 1 ? layout.GetLineEnd(lines - 2) : 0;
                        var start           = lines > 1 ? layout.GetLineStart(layout.LineCount - 2) : 0;
                        switch (lineBreakMode)
                        {
                        case LineBreakMode.HeadTruncation:
                            text = StartTruncatedLastLine(text, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;

                        case LineBreakMode.MiddleTruncation:
                            text = MidTruncatedLastLine(text, paint, secondToLastEnd, layout.GetLineStart(lines - 1), (layout.GetLineEnd(lines - 1) + layout.GetLineStart(lines - 1)) / 2 - 1, start, layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;

                        case LineBreakMode.TailTruncation:
                            text = EndTruncatedLastLine(text, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;

                        default:
                            text = text.Substring(0, layout.GetLineEnd(lines - 1));
                            break;
                        }
                        textFormatted = new Java.Lang.String(text);
                    }
                }
            }
            var result = TextExtensions.StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true);

            return(result);
        }