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)); }
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); }
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); }