internal static float WidthFit(ICharSequence text, TextPaint paint, int lines, float min, float max, int availWidth, int availHeight)
        {
            if (availWidth > int.MaxValue / 3)
            {
                if (availHeight > int.MaxValue / 3)
                {
                    return(max);
                }
                var   fontMetrics     = paint.GetFontMetrics();
                var   fontLineHeight  = fontMetrics.Descent * FontScale - fontMetrics.Ascent * FontScale;
                var   fontLeading     = System.Math.Abs(fontMetrics.Bottom * FontScale - fontMetrics.Descent * FontScale);
                var   fontPixelSize   = paint.TextSize * FontScale;
                var   lineHeightRatio = fontLineHeight / fontPixelSize;
                var   leadingRatio    = fontLeading / fontPixelSize;
                float ans             = ((availHeight / (lines + leadingRatio * (lines - 1))) / lineHeightRatio - 0.1f);
                return(System.Math.Min(ans, max));
            }
            var result = ZeroLinesFit(text, paint, min, max, availWidth, availHeight);

            float step = (result - min) / 5;

            if (step > 0.05f)
            {
                result = DescendingWidthFit(text, paint, lines, min, result, availWidth, availHeight, step);
                while (step > 0.25f)
                {
                    step  /= 5;
                    result = DescendingWidthFit(text, paint, lines, result, result + step * 5, availWidth, availHeight, step);
                }
            }
            return(result);
        }
Beispiel #2
0
        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 - fontMetrics.Ascent;
                //var fontLeading = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent);
                var fontPixelSize   = paint.TextSize;
                var lineHeightRatio = fontLineHeight / fontPixelSize;
                //var leadingRatio = fontLeading / 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    = new 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);
        }
        internal static float ZeroLinesFit(ICharSequence text, TextPaint paint, float min, float max, int availWidth, int availHeight, float lineHeightMultiplier)
        {
            if (availHeight >= 238609294)
            {
                return(max);
            }
            if (availWidth >= 238609294)
            {
                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;
            using (var layout = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 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, lineHeightMultiplier));
                }
                if (height < availHeight)
                {
                    return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight, lineHeightMultiplier));
                }
                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, lineHeightMultiplier));
                }
                if (maxLineWidth < availWidth)
                {
                    return(ZeroLinesFit(text, paint, mid, max, availWidth, availHeight, lineHeightMultiplier));
                }
                return(mid);
            }
        }
Beispiel #4
0
        /// <summary>Define paints.</summary>
        private void InitPaint()
        {
            // Round rectangle paint
            _strokePaint = new Paint
            {
                Color       = _selectedColor.ToColor(),
                AntiAlias   = true,
                StrokeWidth = _strokeWidth
            };
            _strokePaint.SetStyle(Paint.Style.Stroke);


            // Selected paint
            _fillPaint = new Paint
            {
                Color = _selectedColor.ToColor()
            };
            _strokePaint.AntiAlias = true;
            _fillPaint.SetStyle(Paint.Style.FillAndStroke);


            // Selected text paint
            _selectedTextPaint = new TextPaint(PaintFlags.AntiAlias)
            {
                TextSize = _textSize,
                Color    = unchecked ((int)0xffffffff).ToColor()
            };
            _strokePaint.AntiAlias = true;

            // Unselected text paint
            _unselectedTextPaint = new TextPaint(PaintFlags.AntiAlias)
            {
                TextSize = _textSize,
                Color    = _selectedColor.ToColor()
            };

            _strokePaint.AntiAlias = true;
            _textHeightOffset      = -(_selectedTextPaint.Ascent() + _selectedTextPaint.Descent()) * 0.5f;
            _fontMetrics           = _selectedTextPaint.GetFontMetrics();
        }
Beispiel #5
0
        internal static float WidthFit(ICharSequence text, TextPaint paint, int lines, float min, float max, int availWidth, int availHeight)
        {
            //System.Diagnostics.Debug.WriteLine("F9PTextView.WidthFit: availWidth=["+availWidth+"] availHeight=["+availHeight+"]");

            if (availWidth > int.MaxValue / 3)
            {
                if (availHeight > int.MaxValue / 3)
                {
                    return(max);
                }
                var   fontMetrics     = paint.GetFontMetrics();
                var   fontLineHeight  = fontMetrics.Descent - fontMetrics.Ascent;
                var   fontLeading     = System.Math.Abs(fontMetrics.Bottom - fontMetrics.Descent);
                var   fontPixelSize   = paint.TextSize;
                var   lineHeightRatio = fontLineHeight / fontPixelSize;
                var   leadingRatio    = fontLeading / fontPixelSize;
                float ans             = ((availHeight / (lines + leadingRatio * (lines - 1))) / lineHeightRatio - 0.1f);
                if (ans > max)
                {
                    ans = max;
                }
                return(ans);
            }
            var result = ZeroLinesFit(text, paint, min, max, availWidth, availHeight);

            float step = (result - min) / 5;

            if (step > 0.05f)
            {
                result = DescendingWidthFit(text, paint, lines, min, result, availWidth, availHeight, step);
                while (step > 0.25f)
                {
                    step  /= 5;
                    result = DescendingWidthFit(text, paint, lines, result, result + step * 5, availWidth, availHeight, step);
                }
            }
            return(result);
        }
        public override void Draw(Canvas canvas)
        {
            base.Draw(canvas);

            TextPaint paint = new TextPaint();

            paint.AntiAlias = true;
            paint.SetTypeface(Control.Typeface);
            paint.TextSize = myFontSize * scaledDensity;
            paint.Color    = Android.Graphics.Color.Red;

            Paint.FontMetrics metrics = paint.GetFontMetrics();

            Rect bounds = new Rect();

            paint.GetTextBounds(Element.Text, 0, Element.Text.Length, bounds);

            canvas.DrawText(
                Element.Text,
                0.5f * MeasuredWidth - bounds.Left - 0.5f * bounds.Width(),
                0.5f * MeasuredHeight - metrics.Ascent - 0.5f * (metrics.Bottom - metrics.Top),
                paint
                );
        }
Beispiel #7
0
        //bool _truncating;
        internal static StaticLayout Truncate(string text, F9PFormattedString baseFormattedString, TextPaint paint, int availWidth, int availHeight, AutoFit fit, LineBreakMode lineBreakMode, ref int lines, ref ICharSequence textFormatted)
        {
            StaticLayout layout         = null;
            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 = new 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 = baseFormattedString.ToSpannableString(EllipsePlacement.None, 0, 0, layout.GetLineEnd(lines - 1));
                            textFormatted = TruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth);
                            break;
                        }
                    }
                }
                else
                {
                    layout = new 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);
                    }
                }
            }
            return(new StaticLayout(textFormatted, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, true));
        }
#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, float lineHeightMultiplier, ref int lines, ref ICharSequence textFormatted)
#pragma warning restore IDE0060 // Remove unused parameter
        {
            StaticLayout layout         = null;
            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, lineHeightMultiplier, 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;
                        textFormatted?.Dispose();
                        switch (lineBreakMode)
                        {
                        case LineBreakMode.HeadTruncation:
                            textFormatted = StartTruncatedFormatted(baseFormattedString, paint, secondToLastEnd, start, layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier);
                            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, lineHeightMultiplier);
                            break;

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

                        default:
                            textFormatted = TruncatedFormatted(baseFormattedString, paint, secondToLastEnd, layout.GetLineStart(lines - 1), layout.GetLineEnd(layout.LineCount - 1), availWidth, lineHeightMultiplier);
                            break;
                        }
                    }
                }
                else
                {
                    layout = TextExtensions.StaticLayout(text, paint, availWidth, Android.Text.Layout.Alignment.AlignNormal, lineHeightMultiplier, 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, lineHeightMultiplier);
                            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, lineHeightMultiplier);
                            break;

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

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

            layout?.Dispose();
            //textFormatted?.Dispose();  // this causes Bc3.Keypad to break!
            return(result);
        }