Example #1
0
 public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
 {
     if (Control is TextBlock control)
     {
         _fontMetrics = control.GetFontMetrics();
         var desiredSize = InternalMeasure(new Windows.Foundation.Size(widthConstraint, heightConstraint));
         var minSize     = new Xamarin.Forms.Size(10, Element != null ? _fontMetrics.LineHeightForFontSize(Element.DecipheredMinFontSize()) : 10);
         var result      = new SizeRequest(new Xamarin.Forms.Size(desiredSize.Width, desiredSize.Height), minSize);
         return(result);
     }
     return(new SizeRequest(Size.Zero));
 }
Example #2
0
        protected Windows.Foundation.Size InternalMeasure(Windows.Foundation.Size availableSize, TextBlock control = null)
        {
            if (Element is Forms9Patch.Label element)
            {
                control = control ?? Control;
                if (control == null || availableSize.Width <= 0 || availableSize.Height <= 0)
                {
                    _lastAvailableSize = availableSize;
                    _lastElementSize   = element.Bounds.Size;
                    return(new Windows.Foundation.Size(0, 0));
                }
                // Next block was commented out because of failure to render BcNotes in Heights and Areas (in notes popup and on Disclaimer)
                // ... and, by doing so, it broke the picker and the keypad in Heights and Areas.
                if (LayoutValid &&
                    control == Control &&
                    _lastAvailableSize.Width == availableSize.Width &&
                    _lastAvailableSize.Height == availableSize.Height &&
                    _lastElementSize == element.Bounds.Size &&
                    DateTime.Now - _lastMeasure < TimeSpan.FromSeconds(1))
                {
                    return(_lastInternalMeasure);
                }

                element.SetIsInNativeLayout(true);

                var width  = Math.Min(availableSize.Width, int.MaxValue / 2);
                var height = Math.Min(availableSize.Height, int.MaxValue / 2);
                var result = new Windows.Foundation.Size(width, height);

                if (control != null)
                {
                    // reset FontSize
                    var tmpFontSize = element.DecipheredFontSize();

                    if (element.SynchronizedFontSize > element.MinFontSize)
                    {
                        tmpFontSize = element.SynchronizedFontSize;
                    }
                    var minFontSize = element.DecipheredMinFontSize();
                    control.MaxLines  = 0; // int.MaxValue / 3;
                    control.MaxWidth  = double.PositiveInfinity;
                    control.MaxHeight = double.PositiveInfinity;
                    control.MinHeight = 0;
                    control.MinWidth  = 0;

                    control.FontStyle  = element.FontAttributes.HasFlag(FontAttributes.Italic) ? FontStyle.Italic : FontStyle.Normal;
                    control.FontWeight = element.FontAttributes.HasFlag(FontAttributes.Bold) ? FontWeights.Bold : FontWeights.Normal;

                    control.UpdateLineBreakMode(element);

                    control.SetAndFormatText(element, tmpFontSize);
                    control.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                    double tmpHt = control.DesiredSize.Height;
                    _fontMetrics = control.GetFontMetrics();
                    if (element.Lines == 0)
                    {
                        // do our best job to fit the existing space.
                        if (control.DesiredSize.Width - width > -Precision || control.DesiredSize.Height - height > -Precision)
                        {
                            if (DebugCondition)
                            {
                                System.Diagnostics.Debug.WriteLine(GetType() + ".");
                            }
                            tmpFontSize = ZeroLinesFit(element, control, minFontSize, tmpFontSize, width, height);
                            if (DebugCondition)
                            {
                                System.Diagnostics.Debug.WriteLine(GetType() + ".");
                            }
                            control.SetAndFormatText(element, tmpFontSize);
                            control.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                            tmpHt = control.DesiredSize.Height;
                        }
                    }
                    else if (element.AutoFit == AutoFit.Lines)
                    {
                        tmpHt = height;
                        if (height > int.MaxValue / 3)
                        {
                            tmpHt = height = _fontMetrics.HeightForLinesAtFontSize(element.Lines, tmpFontSize);
                        }
                        else
                        {
                            // set the font size to fit Label.Lines into the available height
                            var constrainedSize = control.DesiredSize;

                            tmpFontSize = _fontMetrics.FontSizeFromLinesInHeight(element.Lines, tmpHt);
                            tmpFontSize = FontExtensions.ClipFontSize(tmpFontSize, element);

                            control.SetAndFormatText(element, tmpFontSize);
                            control.Measure(new Windows.Foundation.Size(double.PositiveInfinity, double.PositiveInfinity));
                            if (element.Lines > 1)
                            {
                                var unconstrainedSize = control.DesiredSize;
                                if (unconstrainedSize.Width > constrainedSize.Width)
                                {
                                    control.SetAndFormatText(element, tmpFontSize);
                                    control.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                                }
                            }
                        }
                    }
                    else if (element.AutoFit == AutoFit.Width)
                    {
                        if (control.ActualWidth > control.DesiredSize.Width || control.DesiredSize.Height / control.LineHeight > element.Lines)
                        {
                            tmpFontSize = WidthAndLinesFit(element, control, element.Lines + 1, minFontSize, tmpFontSize, width);
                            control.SetAndFormatText(element, tmpFontSize);
                            control.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                            tmpHt = control.DesiredSize.Height;
                        }
                    }

                    // none of these should happen so let's keep an eye out for it to be sure everything upstream is working
                    if (tmpFontSize > element.DecipheredFontSize())
                    {
                        throw new Exception("fitting somehow returned a tmpFontSize > label.FontSize");
                    }
                    if (tmpFontSize < element.DecipheredMinFontSize())
                    {
                        throw new Exception("fitting somehow returned a tmpFontSize < label.MinFontSize");
                    }
                    // the following doesn't apply when where growing
                    //if (tmpFontSize > label.DecipheredMinFontSize() && (control.DesiredSize.Width > Math.Ceiling(w) || control.DesiredSize.Height > Math.Ceiling(Math.Max(availableSize.Height, label.Height))) )
                    //    throw new Exception("We should never exceed the available bounds if the FontSize is greater than label.MinFontSize");

                    // we needed the following in Android as well.  Xamarin layout really doesn't like this to be changed in real time.
                    if (element != null && Control == control)  // multipicker test was getting here with element and Control both null
                    {
                        if (tmpFontSize == element.FontSize || (element.FontSize == -1 && tmpFontSize == FontExtensions.DefaultFontSize()))
                        {
                            element.FittedFontSize = -1;
                        }
                        else if (Math.Abs(element.FittedFontSize - tmpFontSize) > 1)
                        {
                            element.FittedFontSize = tmpFontSize;
                        }
                    }

                    result           = new Windows.Foundation.Size(Math.Ceiling(control.DesiredSize.Width), Math.Ceiling(tmpHt));
                    control.MaxLines = element.Lines;
                }

                element.SetIsInNativeLayout(false);

                if (control == Control)
                {
                    LayoutValid        = true;
                    _lastAvailableSize = availableSize;
                    _lastElementSize   = element.Bounds.Size;
                    //_lastAutoFit = label.AutoFit;
                    //_lastLines = label.Lines;
                    _lastMeasure         = DateTime.Now;
                    _lastInternalMeasure = result;

                    PrivateArrange(availableSize);
                }
                return(result);
            }
            return(Windows.Foundation.Size.Empty);
        }
Example #3
0
        protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize)
        {
            if (DebugCondition)
            {
                System.Diagnostics.Debug.WriteLine("");
            }


            var label     = Element;
            var textBlock = Control;

            DebugMessage("[" + _measureOverrideInvocation + "] MeasureOverride pre-Enter availableSize=[" + availableSize + "] ElemmentSize=[" + Element.Bounds.Size + "]  PageSize=[" + Xamarin.Forms.Application.Current.MainPage.Bounds.Size + "]");
            DebugMessage("[" + _measureOverrideInvocation + "] \t\t availWidth>=Page.Width=[" + (Math.Round(availableSize.Width) >= Math.Round(Xamarin.Forms.Application.Current.MainPage.Width)) + "]");
            DebugMessage("[" + _measureOverrideInvocation + "] \t\t availHeight>=Page.Height=[" + (Math.Round(availableSize.Height) >= Math.Round(Xamarin.Forms.Application.Current.MainPage.Height)) + "]");
            DebugMessage("[" + _measureOverrideInvocation + "] \t\t Element.Parent=[" + Element.Parent + "]");
            DebugMessage("[" + _measureOverrideInvocation + "] \t\t MeasureOverride FontSize=[" + textBlock.FontSize + "] BaseLineOffset=[" + textBlock.BaselineOffset + "] LineHeight=[" + textBlock.LineHeight + "]");

            if (DebugCondition)
            {
                System.Diagnostics.Debug.WriteLine("");
            }



            if (label == null || textBlock == null || availableSize.Width == 0 || availableSize.Height == 0)
            {
                return(new Windows.Foundation.Size(0, 0));
            }

            //if (Double.IsInfinity(availableSize.Height) && Double.IsInfinity(availableSize.Width))
            //    LayoutValid = false;

            if (LayoutValid && _lastAvailableSize.Width <= availableSize.Width && _lastAvailableSize.Height <= availableSize.Height && _lastElementSize == Element.Bounds.Size && DateTime.Now - _lastMeasure < TimeSpan.FromSeconds(1))
            {
                return(_lastMeasureOverrideResult);
            }

            //_lastAvailableSize = availableSize;
            if (DebugCondition)
            {
                System.Diagnostics.Debug.WriteLine("");
            }

            DebugMessage("[" + _measureOverrideInvocation + "] MeasureOverride ENTER availableSize=[" + availableSize + "]");
            //Element.IsInNativeLayout = true;
            label.SetIsInNativeLayout(true);

            double width  = (Math.Round(availableSize.Width) >= Math.Round(Xamarin.Forms.Application.Current.MainPage.Width)) && label.Width > 0 ? Math.Min(label.Width, availableSize.Width) : availableSize.Width;
            double height = (Math.Round(availableSize.Height) >= Math.Round(Xamarin.Forms.Application.Current.MainPage.Height)) && label.Height > 0 ? Math.Min(label.Height, availableSize.Height) : availableSize.Height;


            if (Double.IsInfinity(availableSize.Width) && (label.Width < 0 || !newElement))
            {
                width = availableSize.Width;
            }
            if (Double.IsInfinity(availableSize.Height) && (label.Height < 0 || !newElement))
            {
                height = availableSize.Height;
            }

            newElement = false;


            if (Element.Width > 0 && Element.Height > 0 && !Double.IsInfinity(width) && !Double.IsInfinity(height))  // This line was causing UWP to fail to correctly update width of BcOperandLabel during editing.
            //if (Element.Width > width && Element.Height > height && !Double.IsInfinity(width) && !Double.IsInfinity(height))
            {
                width  = Math.Max(Element.Width, width);
                height = Math.Max(Element.Height, height);
            }

            DebugMessage("[" + _measureOverrideInvocation + "] \t\t width=[" + width + "] height=[" + height + "]");
            if (DebugCondition)
            {
                System.Diagnostics.Debug.WriteLine("");
            }

            //double width = !double.IsInfinity(availableSize.Width) && label.Width > 0 ? Math.Min(label.Width, availableSize.Width) : availableSize.Width;
            //double height = !double.IsInfinity(availableSize.Height) && label.Height > 0 ? Math.Min(label.Height, availableSize.Height) : availableSize.Height;
            //double width  = availableSize.Width;
            //double height = availableSize.Height;

            var result = new Windows.Foundation.Size(width, height);

            if (textBlock != null)
            {
                // reset FontSize
                var tmpFontSize = label.DecipheredFontSize();

                if (DebugCondition)
                {
                    System.Diagnostics.Debug.WriteLine("");
                }

                if (Element.SynchronizedFontSize > Element.MinFontSize)
                {
                    tmpFontSize = Element.SynchronizedFontSize;
                }
                var minFontSize = label.DecipheredMinFontSize();
                textBlock.MaxLines  = 0; // int.MaxValue / 3;
                textBlock.MaxWidth  = double.PositiveInfinity;
                textBlock.MaxHeight = double.PositiveInfinity;
                textBlock.MinHeight = 0;
                textBlock.MinWidth  = 0;
                //textBlock.LineStackingStrategy = LineStackingStrategy.
                //  textBlock.TextWrapping = TextWrapping.WrapWholeWords;
                UpdateLineBreakMode(textBlock);

                double tmpHt = -1;

                textBlock.SetAndFormatText(label, tmpFontSize);
                textBlock.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                _fontMetrics = textBlock.GetFontMetrics();
                if (label.Lines == 0)
                {
                    // do our best job to fit the existing space.
                    if (textBlock.DesiredSize.Width - width > Precision || textBlock.DesiredSize.Height - height > Precision)
                    {
                        tmpFontSize = ZeroLinesFit(label, textBlock, minFontSize, tmpFontSize, width, height);

                        textBlock.SetAndFormatText(label, tmpFontSize);
                        textBlock.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                    }
                }
                else if (label.AutoFit == AutoFit.Lines)
                {
                    tmpHt = height;
                    if (height > int.MaxValue / 3)
                    {
                        //tmpHt = height = label.Lines * (_fontMetrics.LineHeightForFontSize(tmpFontSize) + ;
                        tmpHt = height = _fontMetrics.HeightForLinesAtFontSize(label.Lines, tmpFontSize);
                    }
                    else
                    {// set the font size to fit Label.Lines into the available height
                        //tmpFontSize = _fontMetrics.FontSizeFromLineHeight(height / label.Lines);
                        tmpFontSize = _fontMetrics.FontSizeFromLinesInHeight(label.Lines, tmpHt);

                        tmpFontSize = FontExtensions.ClipFontSize(tmpFontSize, label);

                        textBlock.SetAndFormatText(label, tmpFontSize);
                        textBlock.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                    }
                }
                else if (label.AutoFit == AutoFit.Width)
                {
                    //if (textBlock.DesiredSize.Height / textBlock.LineHeight > label.Lines)
                    if (textBlock.ActualWidth > textBlock.DesiredSize.Width || textBlock.DesiredSize.Height / textBlock.LineHeight > label.Lines)
                    {
                        tmpFontSize = WidthAndLinesFit(label, textBlock, label.Lines, minFontSize, tmpFontSize, width);

                        textBlock.SetAndFormatText(label, tmpFontSize);
                        textBlock.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                    }
                }
                // autofit is off!
                // No need to do anything at the moment.  Will textBlock.SetAndFormat and textBlock.Measure at the end
                //{
                //    textBlock.SetAndFormatText(label, tmpFontSize);
                //    textBlock?.Measure(new Windows.Foundation.Size(w, double.PositiveInfinity));
                //}

                // none of these should happen so let's keep an eye out for it to be sure everything upstream is working
                if (tmpFontSize > label.DecipheredFontSize())
                {
                    throw new Exception("fitting somehow returned a tmpFontSize > label.FontSize");
                }
                if (tmpFontSize < label.DecipheredMinFontSize())
                {
                    throw new Exception("fitting somehow returned a tmpFontSize < label.MinFontSize");
                }
                // the following doesn't apply when where growing
                //if (tmpFontSize > label.DecipheredMinFontSize() && (textBlock.DesiredSize.Width > Math.Ceiling(w) || textBlock.DesiredSize.Height > Math.Ceiling(Math.Max(availableSize.Height, label.Height))) )
                //    throw new Exception("We should never exceed the available bounds if the FontSize is greater than label.MinFontSize");



                // we needed the following in Android as well.  Xamarin layout really doesn't like this to be changed in real time.
                if (Element != null && Control != null)  // multipicker test was getting here with Element and Control both null
                {
                    if (tmpFontSize == Element.FontSize || (Element.FontSize == -1 && tmpFontSize == FontExtensions.DefaultFontSize()))
                    {
                        if (DebugCondition)
                        {
                            System.Diagnostics.Debug.WriteLine("");
                        }
                        Element.FittedFontSize = -1;
                    }
                    else
                    {
                        if (DebugCondition)
                        {
                            System.Diagnostics.Debug.WriteLine("");
                        }
                        Element.FittedFontSize = tmpFontSize;
                    }
                }
                DebugMessage("[" + _measureOverrideInvocation + "] MeasureOverride Element.FittedFontSize=[" + Element.FittedFontSize + "]");

                /*
                 * var syncFontSize = ((ILabel)label).SynchronizedFontSize;
                 * DebugMessage("[" + _measureOverrideInvocation + "] syncFontSize=[" + syncFontSize+"]");
                 * if (syncFontSize >= 0 && tmpFontSize != syncFontSize)
                 * {
                 *  tmpHt = -1;
                 *  textBlock.SetAndFormatText(label, syncFontSize);
                 *  textBlock.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                 * }
                 * else
                 * {
                 *  textBlock.SetAndFormatText(label, tmpFontSize);
                 *  textBlock.Measure(new Windows.Foundation.Size(width, double.PositiveInfinity));
                 * }
                 */
                result = new Windows.Foundation.Size(Math.Ceiling(textBlock.DesiredSize.Width), Math.Ceiling(tmpHt > -1 ? tmpHt : textBlock.DesiredSize.Height));

                if (DebugCondition && label.Width > 0 && label.Height > 0 && (textBlock.DesiredSize.Width > label.Width || textBlock.DesiredSize.Height > label.Height))
                {
                    System.Diagnostics.Debug.WriteLine("");
                }
                DebugMessage("[" + _measureOverrideInvocation + "] availableSize=[" + availableSize + "] result=[" + result + "] FontSize=[" + textBlock.FontSize + "] LineHeight=[" + textBlock.LineHeight + "] ");
                //System.Diagnostics.Debug.WriteLine("[" + _measureOverrideInvocation + "] MeasureOverride [" + (Element.Text ?? Element.HtmlText)+"] availableSize=[" + availableSize + "] result=[" + result + "] FontSize=[" + textBlock.FontSize + "] LineHeight=[" + textBlock.LineHeight + "] ");

                textBlock.MaxLines = label.Lines;
            }

            label.SetIsInNativeLayout(false);

            DebugMessage("[" + _measureOverrideInvocation + "] MeasureOverride EXIT");

            LayoutValid                = true;
            _lastAvailableSize         = availableSize;
            _lastElementSize           = Element.Bounds.Size;
            _lastAutoFit               = label.AutoFit;
            _lastLines                 = label.Lines;
            _lastMeasure               = DateTime.Now;
            _lastMeasureOverrideResult = result;

            if (DebugCondition)
            {
                _measureOverrideInvocation++;
            }

            return(result);
        }