public override SpecificLayout GetBestLayout(LayoutQuery query) { double width = query.MaxWidth; if (this.pixelWidth > 0) { width = Math.Floor(query.MaxWidth / this.pixelWidth) * this.pixelWidth; } double height = query.MaxHeight; if (this.pixelHeight > 0) { height = Math.Floor(query.MaxHeight / this.pixelHeight) * this.pixelHeight; } if (width != query.MaxWidth || height != query.MaxHeight) { query = query.WithDimensions(width, height); } SpecificLayout internalLayout = this.layoutToManage.GetBestLayout(query); if (internalLayout != null) { Size size = new Size(Math.Ceiling(internalLayout.Width / this.pixelWidth) * this.pixelWidth, Math.Ceiling(internalLayout.Height / this.pixelHeight) * this.pixelHeight); Specific_ContainerLayout result = new Specific_ContainerLayout(null, size, new LayoutScore(), internalLayout, new Thickness(0)); return(this.prepareLayoutForQuery(result, query)); } return(null); }
private SpecificLayout getMinHeightChildLayout(double width) { LayoutQuery childQuery = new MinHeight_LayoutQuery(width, double.PositiveInfinity, this.requiredChildScore); SpecificLayout childLayout = this.subLayout.GetBestLayout(childQuery); return(childLayout); }
private SpecificLayout Query_SubLayout(LayoutQuery query) { numComputations++; /*if (this.true_queryResults.Count == 4) * { * System.Diagnostics.Debug.WriteLine("Lots of queries being sent to " + this.layoutToManage); * }*/ if (!query.Debug) { if (this.true_queryResults.ContainsKey(query)) { ErrorReporter.ReportParadox("Error, layoutCache repeated a query that was already present"); } } SpecificLayout result = this.layoutToManage.GetBestLayout(query); if (!query.Debug) { if (this.true_queryResults.ContainsKey(query)) { ErrorReporter.ReportParadox("Error, layoutCache query results were saved before it completed?"); } query.OnAnswered(this.layoutToManage); this.true_queryResults[query] = result; } return(result); }
public Specific_ScrollLayout(ScrollView view, Size size, LayoutScore score, SpecificLayout sublayout) : base(view, size, score, sublayout, new Thickness()) { this.View = view; if (double.IsInfinity(this.SubLayout.Height)) { ErrorReporter.ReportParadox("Infinite Specific_ScrollLayout height: " + this); } }
// Given a SpecificLayout, sets any necessary properties to make it suitable to return to the caller of GetBestLayout(LayoutQuery) protected SpecificLayout prepareLayoutForQuery(SpecificLayout layout, LayoutQuery query) { if (layout != null) { if (layout.Width < 0 || layout.Height < 0) { ErrorReporter.ReportParadox("Illegal layout size: " + layout.Size); this.GetBestLayout(query); } } int numMatches; //if (query.Debug) { if (query.ProposedSolution_ForDebugging != null) { if (!query.Accepts(query.ProposedSolution_ForDebugging)) { ErrorReporter.ReportParadox("Error: the proposed solution was not valid"); } } if (layout != null && !query.Accepts(layout)) { ErrorReporter.ReportParadox("Error: the returned layout was not valid"); LayoutQuery query2 = query.DebugClone(); this.GetBestLayout(query2); } } if (layout != null) { //layout.Set_SourceParent(this); numMatches = 0; /*foreach (LayoutChoice_Set ancestor in layout.GetAncestors()) * { * if (ancestor == this) * numMatches++; * } * if (numMatches == 0) * ErrorReporter.ReportParadox("Error: the returned layout did not come from this layout"); * if (numMatches > 1) * ErrorReporter.ReportParadox("Error: the returned layout contained multiple ancestors matching this one"); */ layout.SourceQuery = query; } if (this.parents.Count < 1 && !(this is ViewManager)) { throw new InvalidOperationException("No parents assigned to " + this); } query.OnAnswered(this); return(layout); }
private SpecificLayout inferredLayout(LayoutQuery query, SpecificLayout response) { this.inferred_queryResults[query] = response; LayoutQuery_And_Response pair = new LayoutQuery_And_Response(query, response); this.orderedResponses.Add(pair); //this.debugCheck(pair); return(response); }
private SpecificLayout MakeLayout(double width, double height, LayoutQuery layoutQuery) { SpecificLayout layout = this.prepareLayoutForQuery(new Specific_LeafLayout(this.view, new LayoutDimensions(width, height, this.ComputeScore(width, height))), layoutQuery); if (!layoutQuery.Accepts(layout)) { ErrorReporter.ReportParadox("Error; ImageLayout attempted to return an invalid layout result"); } return(layout); }
// returns a Dictionary that maps each view in the tree to its closest containing ancestor layout private Dictionary <View, SpecificLayout> findAncestors(SpecificLayout layout) { Dictionary <View, SpecificLayout> parents = new Dictionary <View, SpecificLayout>(); if (layout != null) { this.addAllParents(layout.GetParticipatingChildren(), layout, parents); } return(parents); }
public override LayoutQuery OptimizedUsingExample(SpecificLayout example) { MinWidth_LayoutQuery result = this; if (this.MaxWidth > example.Width) { result = this.Clone((MinWidth_LayoutQuery)null); result.setMaxWidth(example.Width); } return(result); }
public override LayoutQuery OptimizedUsingExample(SpecificLayout example) { MinHeight_LayoutQuery result = this; if (this.MaxHeight > example.Height) { result = this.Clone((MinHeight_LayoutQuery)null); result.setMaxHeight(example.Height); } return(result); }
public override LayoutQuery OptimizedUsingExample(SpecificLayout example) { MaxScore_LayoutQuery result = this; if (this.MinScore.CompareTo(example.Score) < 0) { result = this.Clone((MaxScore_LayoutQuery)null); result.setMinScore(example.Score); } return(result); }
public override SpecificLayout GetBestLayout(LayoutQuery query) { query = query.WithDefaults(this.defaultsOverride.LayoutDefaults); SpecificLayout result = this.SubLayout.GetBestLayout(query); if (result != null) { result = new OverrideLayoutDefaults_SpecificLayout(result, this.defaultsOverride.ViewDefaults); } return(this.prepareLayoutForQuery(result, query)); }
public override SpecificLayout GetBestLayout(LayoutQuery query) { if (this.true_queryResults == null) { this.Initialize(); } numQueries++; if (numQueries % 10000 == 0) { double rate = (double)numComputations / (double)numQueries; System.Diagnostics.Debug.WriteLine("Overall LayoutCache miss rate: " + numComputations + " of " + numQueries + " = " + rate); if (rate < 0.02) { System.Diagnostics.Debug.WriteLine("Surprisingly high layoutcache hit rate"); } } SpecificLayout fastResult = this.GetBestLayout_Quickly(query); if (query.Debug) { SpecificLayout correctResult = this.Query_SubLayout(query); if (correctResult != null && !query.Accepts(correctResult)) { ErrorReporter.ReportParadox("Error: LayoutCache was given an incorrect response by its sublayout"); } bool correct = true; if (query.PreferredLayout(correctResult, fastResult) != correctResult) { ErrorReporter.ReportParadox("Error: layout cache returned incorrect (superior) result"); query.ProposedSolution_ForDebugging = fastResult; correct = false; } if (query.PreferredLayout(fastResult, correctResult) != fastResult) { ErrorReporter.ReportParadox("Error: layout cache returned incorrect (inferior) result"); query.ProposedSolution_ForDebugging = correctResult; correct = false; } if (!correct) { this.GetBestLayout_Quickly(query); this.Query_SubLayout(query); } this.debugCheck(new LayoutQuery_And_Response(query, fastResult)); return(this.prepareLayoutForQuery(correctResult, query)); } //this.debugCheck(new LayoutQuery_And_Response(query, fastResult)); if (fastResult != null) { fastResult = fastResult.Clone(); } return(this.prepareLayoutForQuery(fastResult, query)); }
public override SpecificLayout GetBestLayout(LayoutQuery query) { SpecificLayout best_specificLayout = null; SpecificLayout debugResult = query.ProposedSolution_ForDebugging; if (debugResult != null) { debugResult = debugResult.Clone(); } List <LayoutChoice_Set> good_sourceLayouts = new List <LayoutChoice_Set>(); LayoutQuery originalQuery = query; foreach (LayoutChoice_Set layoutSet in this.layoutOptions) { if (best_specificLayout != null) { // make the query more strict, so we will only ever get dimensions that are at least as good as this // TODO: figure out why it's not better to use OptimizedPastExample query = query.OptimizedUsingExample(best_specificLayout); } SpecificLayout currentLayout; if (query.Debug) { // if the proposed layout is an option, then be sure to consider it if (debugResult != null && debugResult.GetAncestors().Contains(layoutSet)) { query.ProposedSolution_ForDebugging = debugResult; currentLayout = layoutSet.GetBestLayout(query); query.ProposedSolution_ForDebugging = debugResult; return(this.prepareLayoutForQuery(currentLayout, query)); } } currentLayout = layoutSet.GetBestLayout(query); if (currentLayout != null && query.PreferredLayout(currentLayout, best_specificLayout) == currentLayout) { // keep track of this query (which must be the best so far) best_specificLayout = currentLayout; good_sourceLayouts.Add(layoutSet); if (query.Debug && query.ProposedSolution_ForDebugging != null) { if (query.PreferredLayout(query.ProposedSolution_ForDebugging, best_specificLayout) != query.ProposedSolution_ForDebugging) { ErrorReporter.ReportParadox("Error; query " + query + " prefers " + best_specificLayout + " over proposed debug solution " + query.ProposedSolution_ForDebugging); LayoutQuery debugQuery = query.DebugClone(); layoutSet.GetBestLayout(debugQuery); } } } } originalQuery.ProposedSolution_ForDebugging = debugResult; return(this.prepareLayoutForQuery(best_specificLayout, originalQuery)); }
public bool Accepts(SpecificLayout layout) { if (layout == null) { return(false); } if (layout.GetBestLayout(this) != null) { return(true); } return(false); }
private void debugCheck(LayoutQuery_And_Response queryAndResponse) { // make sure that each query likes its response at least as much as all others SpecificLayout result = queryAndResponse.Response; LayoutQuery query = queryAndResponse.Query; for (int i = 0; i < this.orderedResponses.Count; i++) { LayoutQuery_And_Response other = this.orderedResponses[i]; if (other.Query.PreferredLayout(other.Response, result) != other.Response) { ErrorReporter.ReportParadox("New response is a better solution to previous query than preexisting response.\n" + "Layout : " + this.layoutToManage + "\n" + "Old query : " + other.Query + "\n" + "Old response: " + other.Response + "\n" + "New query : " + query + "\n" + "New response: " + result); LayoutQuery query2 = other.Query.Clone(); query2.Debug = true; query2.ProposedSolution_ForDebugging = result; SpecificLayout oldQueryNewDebugResult = this.GetBestLayout(query2.Clone()); LayoutQuery query1 = query.Clone(); query1.Debug = true; SpecificLayout newQueryDebugResult = this.GetBestLayout(query1.Clone()); System.Diagnostics.Debug.WriteLine("Results from LayoutCache discrepancy: Old query new result = " + oldQueryNewDebugResult + ", New query new result = " + newQueryDebugResult); this.layoutToManage.GetBestLayout(query2.Clone()); this.layoutToManage.GetBestLayout(query1.Clone()); } if (query.PreferredLayout(result, other.Response) != result) { ErrorReporter.ReportParadox("New response is a worse solution to new query than previous response.\n" + "Layout : " + this.layoutToManage + "\n" + "Old query : " + other.Query + "\n" + "Old response: " + other.Response + "\n" + "New query : " + query + "\n" + "New response: " + result); LayoutQuery query1 = query.Clone(); query1.Debug = true; query1.ProposedSolution_ForDebugging = other.Response; SpecificLayout newQueryDebugResult = this.GetBestLayout(query1); LayoutQuery query2 = other.Query.Clone(); query2.Debug = true; SpecificLayout oldQueryNewDebugResult = this.GetBestLayout(query2); System.Diagnostics.Debug.WriteLine("Results from LayoutCache discrepancy: Old query new result = " + oldQueryNewDebugResult + ", New query new result = " + newQueryDebugResult); this.GetBestLayout(query1.Clone()); this.GetBestLayout(query2.Clone()); } } }
private SpecificLayout makeLayout(Size size, SpecificLayout childLayout) { double childHeight = childLayout.Height; if (childHeight == 0) { childHeight = 1; } LayoutScore score = this.resultingScore.Times(size.Height / childHeight); LayoutScore scoreDifference = score.Minus(childLayout.Score); SpecificLayout result = new Specific_ScrollLayout(this.view, size, scoreDifference, childLayout); return(result); }
public override SpecificLayout GetBestLayout(LayoutQuery query) { LayoutQuery parentQuery = query.WithScore(query.MinScore.Minus(this.BonusScore)); SpecificLayout parentResult = base.GetBestLayout(parentQuery); if (parentResult == null) { return(null); } SpecificLayout result = this.makeSpecificLayout(this.View, parentResult.Size, this.BonusScore, parentResult, new Thickness()); this.prepareLayoutForQuery(result, query); return(result); }
private void addAllParents(IEnumerable <SpecificLayout> candidates, SpecificLayout parentView_layout, Dictionary <View, SpecificLayout> accumulator) { foreach (SpecificLayout childLayout in candidates) { if (childLayout.View != null) { accumulator[childLayout.View] = parentView_layout; this.addAllParents(childLayout.GetParticipatingChildren(), childLayout, accumulator); } else { this.addAllParents(childLayout.GetParticipatingChildren(), parentView_layout, accumulator); } } }
public override SpecificLayout GetBestLayout(LayoutQuery query) { Specific_ContainerLayout result; // Determine whether there's room for the border double borderWidth = this.BorderThickness.Left + this.BorderThickness.Right; double borderHeight = this.BorderThickness.Top + this.BorderThickness.Bottom; LayoutQuery subQuery = query.WithDimensions(query.MaxWidth - borderWidth, query.MaxHeight - borderHeight); if (subQuery.MaxWidth < 0 || subQuery.MaxHeight < 0) { return(null); } // Query sublayout if it exists if (this.SubLayout != null) { SpecificLayout best_subLayout = this.SubLayout.GetBestLayout(subQuery); if (best_subLayout != null) { result = this.makeSpecificLayout(this.view, new Size(best_subLayout.Width + borderWidth, best_subLayout.Height + borderHeight), LayoutScore.Zero, best_subLayout, this.BorderThickness); result.ChildFillsAvailableSpace = this.ChildFillsAvailableSpace; this.prepareLayoutForQuery(result, query); return(result); } return(null); } // if there is no subLayout, for now we just return an empty size Specific_ContainerLayout empty = this.makeSpecificLayout(this.view, new Size(), LayoutScore.Zero, null, new Thickness()); if (query.Accepts(empty)) { result = empty; } else { result = null; } this.prepareLayoutForQuery(result, query); return(result); }
// returns whichever layout it likes better public SpecificLayout PreferredLayout(SpecificLayout tieWinner, SpecificLayout tieLoser) { if (!this.Accepts(tieWinner)) { if (this.Accepts(tieLoser)) { return(tieLoser); } else { return(null); } } if (!this.Accepts(tieLoser)) { return(tieWinner); } LayoutDimensions dimensions1 = new LayoutDimensions(); dimensions1.Width = tieWinner.Width; dimensions1.Height = tieWinner.Height; dimensions1.Score = tieWinner.Score; LayoutDimensions dimensions2 = new LayoutDimensions(); dimensions2.Width = tieLoser.Width; dimensions2.Height = tieLoser.Height; dimensions2.Score = tieLoser.Score; // TODO: when asking a MaxScore_LayoutQuery which layout it likes better, consider calling isScoreAtLeast instead of computing all the scores if (this.PreferredLayout(dimensions1, dimensions2) == dimensions1) { return(tieWinner); } else { return(tieLoser); } }
// returns a stricter query that won't even be satisfied by this example public LayoutQuery OptimizedPastExample(SpecificLayout example) { return(this.OptimizedPastDimensions(example.Dimensions)); }
// Attempts to find a strictly larger query so we can get an upper bound on the required size (and if possible, we want a query whose response is accepted by the original) private LayoutQuery_And_Response Find_LargerQuery(LayoutQuery query) { LayoutQuery_And_Response bestResult = null; // check each previous query and response to see if we can use one of them // TODO do something faster and more complicated that doesn't entail checking every query, using something like an R-tree foreach (LayoutQuery_And_Response queryAndResponse in this.orderedResponses) { LayoutQuery otherQuery = queryAndResponse.Query; SpecificLayout otherResult = queryAndResponse.Response; // check whether the answer to the previous query must also be the answer to the current query bool otherEncompassesInputs = true; bool otherEncompassesOutputs = true; bool inputAccepted = true; bool thisEncompassesInputs = true; // If we're looking for the min width or min height, then tightening the score means we can't necessarily use the other result as the best result if (query.MaximizesScore()) { if (otherQuery.MaxWidth < query.MaxWidth) { otherEncompassesInputs = false; } if (otherQuery.MaxWidth > query.MaxWidth) { thisEncompassesInputs = false; } if (otherQuery.MaxHeight < query.MaxHeight) { otherEncompassesInputs = false; } if (otherQuery.MaxHeight > query.MaxHeight) { thisEncompassesInputs = false; } if (otherQuery.MinScore.CompareTo(query.MinScore) > 0) { otherEncompassesOutputs = false; } if (otherResult == null || otherResult.Width > query.MaxWidth) { inputAccepted = false; } if (otherResult == null || otherResult.Height > query.MaxHeight) { inputAccepted = false; } } if (query.MinimizesWidth()) { if (otherQuery.MaxWidth < query.MaxWidth) { otherEncompassesOutputs = false; } if (otherQuery.MaxHeight < query.MaxHeight) { otherEncompassesInputs = false; } if (otherQuery.MaxHeight > query.MaxHeight) { thisEncompassesInputs = false; } if (otherQuery.MinScore.CompareTo(query.MinScore) > 0) { otherEncompassesInputs = false; } if (otherQuery.MinScore.CompareTo(query.MinScore) < 0) { thisEncompassesInputs = false; } if (otherResult == null || otherResult.Score.CompareTo(query.MinScore) < 0) { inputAccepted = false; } if (otherResult == null || otherResult.Height > query.MaxHeight) { inputAccepted = false; } } if (query.MinimizesHeight()) { if (otherQuery.MaxWidth < query.MaxWidth) { otherEncompassesInputs = false; } if (otherQuery.MaxWidth > query.MaxWidth) { thisEncompassesInputs = false; } if (otherQuery.MaxHeight < query.MaxHeight) { otherEncompassesOutputs = false; } if (otherQuery.MinScore.CompareTo(query.MinScore) > 0) { otherEncompassesInputs = false; } if (otherQuery.MinScore.CompareTo(query.MinScore) < 0) { thisEncompassesInputs = false; } if (otherResult == null || otherResult.Width > query.MaxWidth) { inputAccepted = false; } if (otherResult == null || otherResult.Score.CompareTo(query.MinScore) < 0) { inputAccepted = false; } } if (otherEncompassesInputs) { if (query.SameType(otherQuery) && query.Accepts(otherResult)) { // The previous query had looser inputs but its result was still in our range, so we know its result will be right for us too return(queryAndResponse); } if (query.SameType(otherQuery) && inputAccepted && otherEncompassesOutputs) { if (!query.Accepts(otherResult)) { // The previous query had looser inputs, and demonstrated that the best output is worse than our threshold // So, our current query has no solution return(new LayoutQuery_And_Response(otherQuery, null)); } } if (otherEncompassesOutputs && otherResult == null) { // The previous query had looser inputs and looser outputs but no solution, so the current query will also have no solution return(queryAndResponse); } if (query.SameType(otherQuery) && thisEncompassesInputs) { if (otherResult != null) { // If we already asked the same question then we already know what the best answer is // We just have to double-check whether the best answer is good enough if (query.Accepts(otherResult)) { return(queryAndResponse); } else { return(new LayoutQuery_And_Response(otherQuery, null)); } } } } } if (query.Debug) { if (bestResult != null && bestResult.Response != null && !bestResult.Query.Accepts(bestResult.Response)) { ErrorReporter.ReportParadox("Query does not accept its recorded answer"); } } // return the most useful query+response that we found return(bestResult); }
public OverrideLayoutDefaults_SpecificLayout(SpecificLayout sublayout, ViewDefaults defaultsOverride) : base(null, sublayout.Size, LayoutScore.Zero, sublayout, new Thickness(0)) { this.defaultsOverride = defaultsOverride; }
public Specific_ContainerLayout(View view, Size size, LayoutScore bonusScore, SpecificLayout subLayout, Thickness borderThickness) { this.Initialize(); this.view = view; this.Size = size; this.bonusScore = bonusScore; this.BorderThickness = borderThickness; this.subLayout = subLayout; }
// redoes the layout private void DoLayout() { this.needsRelayout = false; // determine which views are currently focused so we can re-focus them after redoing the layout List <View> focusedViews = new List <View>(); if (this.specificLayout != null) { foreach (SpecificLayout layout in this.specificLayout.GetDescendents()) { if (layout.View != null && layout.View.IsFocused && layout.GetParticipatingChildren().Count() < 1) { focusedViews.Add(layout.View); } } } // check some data in preparation for computing stats int num_grid_preComputations = GridLayout.NumComputations; DateTime startTime = DateTime.Now; // record the parent of each view before the relayout, to help us know which parents to disconnect Dictionary <View, SpecificLayout> preParents = this.findAncestors(this.specificLayout); // recompute the new desired layout // generally we expect the overall score to be positive, so we start by hypothesizing // that there exists a layout with positive score, and only checking negative-scoring layouts if no positive-scoring layout is found LayoutQuery query = new MaxScore_LayoutQuery(this.displaySize.Width, this.displaySize.Height, LayoutScore.Zero, this.visualDefaults.LayoutDefaults); DateTime getBestLayout_startDate = DateTime.Now; this.specificLayout = this.GetSublayout().GetBestLayout(query); if (this.specificLayout == null) { query = query.WithScore(LayoutScore.Minimum); this.specificLayout = this.GetSublayout().GetBestLayout(query); } DateTime getBestLayout_endDate = DateTime.Now; // find the parent of each view after the relayout, to help us know which parents to disconnect Dictionary <View, SpecificLayout> postParents = this.findAncestors(this.specificLayout); // disconnect any parents that are no longer the same foreach (View view in preParents.Keys) { SpecificLayout preLayout = preParents[view]; if (preLayout != null) { SpecificLayout postLayout = this.DictionaryGet(postParents, view); if (postLayout == null || preLayout.View != postLayout.View) { // The parent of <view> has changed. // Disconnect it from the previous parent. preLayout.Remove_VisualDescendent(view); } } } // record that our layout is up-to-date (so any future updates will trigger a relayout) this.Reset_ChangeAnnouncement(); // update our actual view this.mainView.Content = this.specificLayout.DoLayout(displaySize, this.visualDefaults.ViewDefaults); // Inform each layout whose view was reattached, in case they need to restore any state that can only be restored after being reattached (most likely because the view system would overwrite it) foreach (SpecificLayout layout in postParents.Values) { layout.AfterLayoutAttached(); } // display stats DateTime endTime = DateTime.Now; TimeSpan duration = endTime.Subtract(startTime); System.Diagnostics.Debug.WriteLine("ViewManager DoLayout finished in " + duration + " (" + query.Cost + ") queries"); System.Diagnostics.Debug.WriteLine("Text formatting time = " + TextLayout.TextTime + " for " + TextLayout.NumMeasures + " measures"); int num_grid_postComputations = GridLayout.NumComputations; System.Diagnostics.Debug.WriteLine("Num grid computations = " + (num_grid_postComputations - num_grid_preComputations)); TextLayout.NumMeasures = 0; TextLayout.TextTime = new TimeSpan(); // refocus the previously focused views foreach (View view in focusedViews) { if (postParents.ContainsKey(view)) { view.Focus(); } } System.Diagnostics.Debug.WriteLine("ViewManager completed layout at " + DateTime.Now); if (this.LayoutCompleted != null) { ViewManager_LayoutStats stats = new ViewManager_LayoutStats(); stats.ViewManager_LayoutDuration = duration; stats.ViewManager_getBestLayout_Duration = getBestLayout_endDate.Subtract(getBestLayout_startDate); this.LayoutCompleted.Invoke(stats); } }
public void CopyFrom(SpecificLayout original) { base.CopyFrom(original); this.SourceQuery = original.SourceQuery; //this.ancestors = new List<LayoutChoice_Set>(original.ancestors); }
protected Specific_ContainerLayout makeSpecificLayout(View view, Size size, LayoutScore bonusScore, SpecificLayout subLayout, Thickness border) { return(new Specific_ContainerLayout(view, size, bonusScore, subLayout, border)); }
private SpecificLayout GetBestLayout_Quickly(LayoutQuery query) { SpecificLayout result = null; // A layout of size 0 in one dimension doesn't get any points for being nonzero in the other dimension if ((query.MaxHeight == 0) != (query.MaxWidth == 0)) { result = this.GetBestLayout_Quickly(this.SizeZeroQuery); if (query.Accepts(result)) { return(result); } return(null); } // check whether we've previously saved the result if (!query.Debug) { if (this.true_queryResults.TryGetValue(query, out result) || this.inferred_queryResults.TryGetValue(query, out result)) { if (result != null) { return(result); } return(null); } } // the result wasn't saved, so we need to delegate the layout query // However, we might first be able to make the query more strict LayoutQuery_And_Response broadened = this.Find_LargerQuery(query); if (broadened != null) { if (query.Debug) { LayoutQuery debugQuery = query.Clone(); debugQuery.Debug = true; SpecificLayout correct_subLayout = this.Query_SubLayout(debugQuery); if (broadened.Query.PreferredLayout(broadened.Response, correct_subLayout) != broadened.Response) { ErrorReporter.ReportParadox("Error; incorrect result for broadened query: broadened query " + broadened.Query + " returned " + broadened.Response + " whereas the response from the sublayout for debug query " + debugQuery + " is " + correct_subLayout); LayoutQuery debugQuery2 = broadened.Query.DebugClone(); debugQuery2.ProposedSolution_ForDebugging = correct_subLayout; this.GetBestLayout(debugQuery2); } } return(this.inferredLayout(query, broadened.Response)); } LayoutQuery_And_Response shrunken = this.FindExample(query); if (query.Debug) { if (shrunken != null) { LayoutQuery debugQuery = shrunken.Query.Clone(); debugQuery.Debug = true; SpecificLayout correct_subLayout = this.Query_SubLayout(debugQuery); if (shrunken.Query.PreferredLayout(shrunken.Response, correct_subLayout) != shrunken.Response) { ErrorReporter.ReportParadox("Error; incorrect result for shrunken query"); } } } if (shrunken != null) { // If the existing example is already at the extreme, then use it if (query.MaximizesScore()) { if (shrunken.Response.Width >= query.MaxWidth && shrunken.Response.Height >= query.MaxHeight) { return(this.inferredLayout(query, shrunken.Response)); } } if (query.MinimizesWidth()) { if (shrunken.Response.Width <= 0) { return(this.inferredLayout(query, shrunken.Response)); } } if (query.MinimizesHeight()) { if (shrunken.Response.Height <= 0) { return(this.inferredLayout(query, shrunken.Response)); } } } // if we couldn't immediately return a result using the cache, we can still put a bound on the results we might get // They have to be at least as good as the sample we found if (shrunken != null) { // First, see if we can improve past what we currently have LayoutQuery strictlyImprovedQuery = query.OptimizedPastExample(shrunken.Response); bool allowCache = !strictlyImprovedQuery.Accepts(shrunken.Response); // Ask the sublayout for this result (or use the cache if we've already asked) if (allowCache) { result = this.GetBestLayout_Quickly(strictlyImprovedQuery); } else { result = this.Query_SubLayout(strictlyImprovedQuery); } if (result == null) { result = shrunken.Response; } return(this.inferredLayout(query, result)); } else { result = this.Query_SubLayout(query); } if (result == null) { if (shrunken != null && query.Accepts(shrunken.Response)) { ErrorReporter.ReportParadox("Error: cache contains an acceptable value for the current query, but the layout claims there are none"); result = shrunken.Response; } } // record that this is the exact answer to this query LayoutQuery_And_Response queryAndResponse = new LayoutQuery_And_Response(query, result); this.orderedResponses.Add(queryAndResponse); //this.debugCheck(queryAndResponse); if (result != null) { result = result.Clone(); } return(result); }
// tests that the layout satisfies all of the queries consistently public void DebugCheck(LayoutChoice_Set layout) { int i, j; int maxWidth, maxHeight; maxWidth = 127; maxHeight = 127; LayoutDimensions[,] maxScore_dimensions = new LayoutDimensions[maxWidth, maxHeight]; LayoutDimensions[,] minWidth_dimensions = new LayoutDimensions[maxWidth, maxHeight]; LayoutDimensions[,] minHeight_dimensions = new LayoutDimensions[maxWidth, maxHeight]; for (i = 0; i < maxWidth; i++) { System.Diagnostics.Debug.WriteLine(i.ToString() + " of " + maxWidth.ToString()); for (j = 0; j < maxHeight; j++) { int width = i + 29; int height = j; // find the maximum score of all layouts that fit in these dimensions LayoutQuery maxScoreQuery = new MaxScore_LayoutQuery(width, height, LayoutScore.Minimum, this.visualDefaults.LayoutDefaults); SpecificLayout maxScore_layout = layout.GetBestLayout(maxScoreQuery); maxScore_dimensions[i, j] = maxScore_layout.Dimensions; // find the layout of minimum width having at least this score LayoutQuery minWidthQuery = new MinWidth_LayoutQuery(width, height, maxScore_layout.Score, this.visualDefaults.LayoutDefaults); SpecificLayout minWidth_layout = layout.GetBestLayout(minWidthQuery); if (minWidth_layout != null) { minWidth_dimensions[i, j] = minWidth_layout.Dimensions; } // find the layout of minimum height having at least this score LayoutQuery minHeightQuery = new MinHeight_LayoutQuery(width, height, maxScore_layout.Score, this.visualDefaults.LayoutDefaults); SpecificLayout minHeight_layout = layout.GetBestLayout(minHeightQuery); if (minHeight_layout != null) { minHeight_dimensions[i, j] = minHeight_layout.Dimensions; } if (i > 0) { if (maxScore_dimensions[i, j].Score.CompareTo(maxScore_dimensions[i - 1, j].Score) < 0) { System.Diagnostics.Debug.WriteLine("Error: inconsistency between (" + i.ToString() + ", " + j.ToString() + ") and (" + (i - 1).ToString() + ", " + j.ToString() + ")"); } } if (j > 0) { if (maxScore_dimensions[i, j].Score.CompareTo(maxScore_dimensions[i, j - 1].Score) < 0) { System.Diagnostics.Debug.WriteLine("Error: inconsistency between (" + i.ToString() + ", " + j.ToString() + ") and (" + i.ToString() + ", " + (j - 1).ToString() + ")"); } } if ((width == 0 || height == 0) && maxScore_dimensions[i, j].Score.CompareTo(LayoutScore.Zero) > 0) { System.Diagnostics.Debug.WriteLine("Error: clipping not noticed at (" + i.ToString() + ", " + j.ToString() + ")"); } if (minWidth_dimensions[i, j] == null) { System.Diagnostics.Debug.WriteLine("Error: minWidth query for (" + i.ToString() + ", " + j.ToString() + ") returned null"); minWidthQuery.Debug = true; layout.GetBestLayout(minWidthQuery.Clone()); } if (minHeight_dimensions[i, j] == null) { System.Diagnostics.Debug.WriteLine("Error: minHeight query for (" + i.ToString() + ", " + j.ToString() + ") returned null"); } if (i > 0 && minWidth_dimensions[i, j] != null && minWidth_dimensions[i, j] != null) { if (minWidth_dimensions[i, j].Score.CompareTo(minWidth_dimensions[i - 1, j].Score) == 0) { if (minWidth_dimensions[i, j].Width != minWidth_dimensions[i - 1, j].Width) { System.Diagnostics.Debug.WriteLine("Error: width is wrong in minWidth query between (" + i.ToString() + ", " + j.ToString() + ") and (" + (i - 1).ToString() + ", " + j.ToString() + ")"); } } } if (j > 0 && minHeight_dimensions[i, j] != null && minHeight_dimensions[i, j] != null) { if (minHeight_dimensions[i, j].Score.CompareTo(minHeight_dimensions[i, j - 1].Score) == 0) { if (minHeight_dimensions[i, j].Height != minHeight_dimensions[i, j - 1].Height) { System.Diagnostics.Debug.WriteLine("Error: height is wrong in minHeight query between (" + i.ToString() + ", " + j.ToString() + ") and (" + i.ToString() + ", " + (j - 1).ToString() + ")"); minHeightQuery.Debug = true; layout.GetBestLayout(minHeightQuery.Clone()); } } } } } System.Diagnostics.Debug.WriteLine("done with debugCheck"); /* * System.Diagnostics.Debug.WriteLine("checking minWidth queries"); * for (i = 1; i < maxWidth; i++) * { * for (j = 1; j < maxHeight; j++) * { * if (maxScore_dimensions[i, j].Score.CompareTo(maxScore_dimensions[i - 1, j] < 0)) * System.Diagnostics.Debug.WriteLine("Error: inconsistency between (" + i.ToString() + ", " + j.ToString() + ") and (" + (i - 1).ToString() + ", " + j.ToString()); * if (maxScore_dimensions[i, j].Score.CompareTo(maxScore_dimensions[i, j - 1] < 0)) * System.Diagnostics.Debug.WriteLine("Error: inconsistency between (" + i.ToString() + ", " + j.ToString() + ") and (" + i.ToString() + ", " + (j - 1).ToString()); * } * }*/ }