public void CopyFrom(Specific_TextLayout original) { this.width = original.width; this.height = original.height; this.fontSize = original.fontSize; this.textItem = original.textItem; }
// compute the best dimensions fitting within the given size private Specific_TextLayout ComputeDimensions(Size availableSize, bool debug) { DateTime start = DateTime.Now; numComputations++; FormattedParagraph formattedText = this.formatText(availableSize.Width, debug, this.FontSize); Size desiredSize = formattedText.Size; if (desiredSize.Width < 0 || desiredSize.Height < 0) { ErrorReporter.ReportParadox("Illegal size " + desiredSize + " returned by textFormatter.FormatText"); } bool cropped = false; double width, height; // assign the width, height, and score if (desiredSize.Width <= availableSize.Width && desiredSize.Height <= availableSize.Height) { // no cropping is necessary width = desiredSize.Width; height = desiredSize.Height; } else { // cropping cropped = true; if (this.ScoreIfCropped) { width = Math.Min(desiredSize.Width, availableSize.Width); height = Math.Min(desiredSize.Height, availableSize.Height); } else { width = height = 0; } } Specific_TextLayout specificLayout = new Specific_TextLayout(this.TextItem_Configurer, width, height, this.FontSize, this.ComputeScore(desiredSize, availableSize, this.TextToFit, formattedText.Text), formattedText.Text, desiredSize); specificLayout.Cropped = cropped; // diagnostics if (this.LoggingEnabled) { DateTime end = DateTime.Now; TimeSpan duration = end.Subtract(start); System.Diagnostics.Debug.WriteLine("spent " + duration + " to measure '" + this.Summarize(this.TextToFit) + "' in " + availableSize + "; desired " + desiredSize + " (formatted = " + this.Summarize(formattedText.Text) + "); requesting " + specificLayout.Size); } return(specificLayout); }
private void considerAnnouncingChanges() { if (this.LoggingEnabled) { System.Diagnostics.Debug.WriteLine("considerAnnouncingChanges textItem_text = " + this.textItem_text + " Text = " + this.Text); } if (this.Get_ChangedSinceLastRender()) { return; } bool mustRedraw = false; if (!this.ScoreIfEmpty && (this.Text == "" || this.Text == null || this.textItem_text == "" || this.textItem_text == null)) { mustRedraw = true; } else { View view = this.TextItem_Configurer.View; Size currentSize = new Size(view.Width, view.Height); Specific_TextLayout layoutForCurrentText = this.ComputeDimensions(currentSize, false); this.TextItem_Text = this.Text; this.layoutsByWidth = new Dictionary <double, FormattedParagraph>(); Specific_TextLayout layoutForNewText = this.ComputeDimensions(currentSize, false); LayoutScore oldScore = layoutForCurrentText.Score; LayoutScore newScore = layoutForNewText.Score; if (!oldScore.Equals(newScore)) { // Something about the score would change if we keep the same size and use the new text // Maybe we suddenly need more space and should ask for it // Maybe we suddenly have enough space and we might become an interesting layout that permits a different font size // In either of these cases, we want to recalculate the layout size mustRedraw = true; } else { // The score didn't change with the new text and the old layout size // So, the user probably isn't interested in having us recompute the layout dimensions mustRedraw = false; this.TextItem_Configurer.DisplayText = layoutForNewText.DisplayText; } if (this.LoggingEnabled) { System.Diagnostics.Debug.WriteLine("TextLayout calculating: Have size: " + currentSize + ". Old text: " + layoutForCurrentText.DisplayText + ". Old target: " + layoutForCurrentText.DesiredSizeForDebugging + ". New text: " + layoutForNewText.DisplayText + ". New target: " + layoutForNewText.DesiredSizeForDebugging); } } this.AnnounceChange(mustRedraw); }
// computes the size of the highest-scoring layout satisfying the given criteria private SpecificLayout Get_MaxScoring_Layout(LayoutQuery query) { if (query.MaxWidth < 0 || query.MaxHeight < 0) { return(null); } Specific_TextLayout specificLayout = this.ComputeDimensions(new Size(query.MaxWidth, query.MaxHeight), query.Debug); if (query.Accepts(specificLayout)) { return(this.prepareLayoutForQuery(specificLayout, query)); } return(null); }
// computes the size of the layout with smallest height satisfying the given criteria private SpecificLayout Get_MinHeight_Layout(LayoutQuery query) { if (query.MaxWidth < 0 || query.MaxHeight < 0) { return(null); } // first check whether this query will accept a cropped layout Specific_TextLayout specificLayout = this.ComputeDimensions(new Size(0, 0), query.Debug); if (query.Accepts(specificLayout)) { return(this.prepareLayoutForQuery(specificLayout, query)); } specificLayout = this.ComputeDimensions(new Size(query.MaxWidth, query.MaxHeight), query.Debug); if (query.Accepts(specificLayout)) { return(this.prepareLayoutForQuery(specificLayout.GetBestLayout(query), query)); } return(null); }
// computes the size of the layout with smallest width satisfying the given criteria private SpecificLayout Get_MinWidth_Layout(LayoutQuery query) { if (query.MaxWidth < 0 || query.MaxHeight < 0) { return(null); } // first check whether this query will accept a cropped layout Specific_TextLayout specificLayout = this.ComputeDimensions(new Size(0, 0), query.Debug); if (query.Accepts(specificLayout)) { return(this.prepareLayoutForQuery(specificLayout, query)); } // not satisfied with cropping so we need to try harder to do a nice-looking layout Specific_TextLayout nonCropping_layout = this.Get_NonCropping_MinWidthLayout(query); if (nonCropping_layout != null) { return(this.prepareLayoutForQuery(nonCropping_layout, query)); } return(null); }
// computes the layout dimensions of the layout of minimum width such that there is no cropping private Specific_TextLayout Get_NonCropping_MinWidthLayout(LayoutQuery query) { Specific_TextLayout bestAllowedDimensions = this.ComputeDimensions(new Size(double.PositiveInfinity, double.PositiveInfinity), query.Debug); double pixelSize = 1; double maxRejectedWidth = 0; int numIterations = 0; bool firstIteration = true; double maxWidth = query.MaxWidth; while (maxRejectedWidth < bestAllowedDimensions.Width - pixelSize / 2) { numIterations++; // given the current width, compute the required height Specific_TextLayout newDimensions = this.ComputeDimensions(new Size(maxWidth, double.PositiveInfinity), query.Debug); if (newDimensions.Height <= query.MaxHeight && query.MinScore.CompareTo(newDimensions.Score) <= 0) { // this layout fits in the required dimensions if (newDimensions.Width <= bestAllowedDimensions.Width && newDimensions.Width <= query.MaxWidth) { // this layout is at least as good as the best layout we found so far bestAllowedDimensions = newDimensions; maxWidth = newDimensions.Width; } else { // we've found a layout having sufficiently small width and height, but it isn't any better than what we'd previously found // So, we're not making progress with this process and should quit break; } } else { // this layout does not fit in the required dimensions if (maxWidth > maxRejectedWidth) { maxRejectedWidth = maxWidth; } // if the first layout we found was too tall, then there will need to be some cropping if (double.IsPositiveInfinity(bestAllowedDimensions.Width)) { return(null); } } // calculate a new size, by guessing based on required area double desiredArea = newDimensions.Height * Math.Max(maxWidth, newDimensions.Width); maxWidth = desiredArea / query.MaxHeight; // Make sure that the next value we check is inside the range that we haven't checked yet, to make sure we're making progress // If our area-based is outside the unexplored range, then from now on just split the remaining range in half on each iteration if (maxWidth < (maxRejectedWidth + pixelSize / 2)) { if (firstIteration) { // The first time that we find we have enough area to make the width very tiny, we calculate the true minimum amount of width required Size desiredSize = this.formatText(maxWidth, query.Debug, this.FontSize).Size; if (desiredSize.Width > maxWidth) { maxRejectedWidth = desiredSize.Width - pixelSize / 2; } maxWidth = desiredSize.Width; } else { // The second time we find that we have enough area to make the width very tiny, we don't recalculate the true min width required because we already did // Instead we just do a binary search maxWidth = (maxRejectedWidth + bestAllowedDimensions.Width) / 2; } } else { if (maxWidth > (bestAllowedDimensions.Width - pixelSize / 2)) { maxWidth = (maxRejectedWidth + bestAllowedDimensions.Width) / 2; } } firstIteration = false; } if (this.LoggingEnabled) { System.Diagnostics.Debug.WriteLine("Spent " + numIterations + " iterations in Get_NonCropping_MinWidthLayout with query = " + query + " and text length = " + this.TextLength); } if (!query.Accepts(bestAllowedDimensions)) { return(null); } return(bestAllowedDimensions); }
public override SpecificLayout Clone() { Specific_TextLayout clone = new Specific_TextLayout(this.textItem, this.width, this.height, this.fontSize, this.score, this.DisplayText, this.DesiredSizeForDebugging); return(clone); }