Last active
October 3, 2020 00:43
-
-
Save krypt-lynx/aac8129b8dd9525c7585435f5dd19f96 to your computer and use it in GitHub Desktop.
column widths using Cassowary algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static bool RecacheColumnWidths_prefix(PawnTable __instance) | |
{ | |
ClSimplexSolver solver = new ClSimplexSolver(); | |
solver.AutoSolve = false; | |
var cachedColumnWidths = (List<float>)typeof(PawnTable) | |
.GetField("cachedColumnWidths", BindingFlags.NonPublic | BindingFlags.Instance) | |
.GetValue(__instance); | |
var def = (PawnTableDef)typeof(PawnTable) | |
.GetField("def", BindingFlags.NonPublic | BindingFlags.Instance) | |
.GetValue(__instance); | |
var cachedSize = (Vector2)typeof(PawnTable) | |
.GetField("cachedSize", BindingFlags.NonPublic | BindingFlags.Instance) | |
.GetValue(__instance); | |
float width = cachedSize.x - 16f; | |
List<float> columnOptimal = new List<float>(); | |
// variables representing column widths | |
List<ClVariable> columnVars = new List<ClVariable>(); | |
// expression for summ of column widths | |
ClLinearExpression widthExpr = new ClLinearExpression(); | |
HashSet<int> distinctPriorities = new HashSet<int>(); | |
// summ of optimal column widths | |
float optimalWidth = 0; | |
foreach (var column in def.columns) | |
{ | |
float optimalColumnWidth; | |
if (column.ignoreWhenCalculatingOptimalTableSize) | |
{ | |
optimalColumnWidth = 0; | |
} | |
else | |
{ | |
optimalColumnWidth = GetOptimalWidth(__instance, column); | |
} | |
optimalWidth += optimalColumnWidth; | |
columnOptimal.Add(optimalColumnWidth); | |
var columnVar = new ClVariable(column.defName); // name is used for debug purposes only | |
columnVars.Add(columnVar); | |
widthExpr.AddExpression(columnVar); // building summ | |
distinctPriorities.Add(column.widthPriority); | |
} | |
// variable representing flexability of columns. Will be equal to 1 if all column widths are optimal and something else if not. | |
var flex = new ClVariable("flex"); | |
// constraining summ of column widths to window width | |
solver.AddConstraint(widthExpr ^ width, ClStrength.Strong); | |
// To make prorities work sorting them in order and using order as priority in solver | |
// And hope for the best, because of priorities bug. | |
// But we are fine if we have less then 10 different priorities (2^n < 1000) | |
var priorities = distinctPriorities.ToList(); | |
priorities.Sort(); | |
var orderForPriority = priorities.Select((x, i) => (x, i)).ToDictionary(xi => xi.Item1, xi => xi.Item2); | |
// to make columns with equal priorities break together bind them together with ClStrength.Strong priority | |
var priorityVars = priorities.Select(x => new ClVariable($"priority_{x}")).ToArray(); | |
for (int i = 0; i < def.columns.Count; i++) | |
{ | |
var column = def.columns[i]; | |
var p = orderForPriority[column.widthPriority]; | |
var columnWidthExpr = priorityVars[p] * columnOptimal[i] * width / optimalWidth - columnVars[i]; // == 0. Equation for width proportional resize | |
solver.AddConstraint(new ClLinearConstraint(columnWidthExpr, ClStrength.Strong)); | |
solver.AddConstraint(columnVars[i] >= GetMinWidth(__instance, column), ClStrength.Medium); | |
solver.AddConstraint(columnVars[i] <= GetMaxWidth(__instance, column), ClStrength.Medium); | |
} | |
for (int i = 0; i < priorities.Count; i++) | |
{ | |
var priorityVar = priorityVars[i]; | |
// binding priority variables to flex var | |
solver.AddConstraint(new ClLinearConstraint(priorityVar - flex, ClStrength.Weak, Mathf.Pow(2, i))); | |
} | |
// do the magic | |
solver.Solve(); | |
// copy results to widths cache | |
cachedColumnWidths.Clear(); | |
for (int i = 0; i < def.columns.Count; i++) | |
{ | |
cachedColumnWidths.Add((float)columnVars[i].Value); | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment