diff --git a/DesertPaintLab.csproj b/DesertPaintLab.csproj
--- a/DesertPaintLab.csproj
+++ b/DesertPaintLab.csproj
@@ -84,6 +84,7 @@
+
diff --git a/PaintRecipe.cs b/PaintRecipe.cs
--- a/PaintRecipe.cs
+++ b/PaintRecipe.cs
@@ -101,6 +101,17 @@ namespace DesertPaintLab
}
}
+ override public string ToString()
+ {
+ string result = Palette.FindNearest(ReactedColor);
+ result += " |";
+ foreach (RecipeIngredient ingr in recipe)
+ {
+ result += " " + ingr.ToString();
+ }
+ return result;
+ }
+
public List Ingredients
{
get {
diff --git a/PlayerProfile.cs b/PlayerProfile.cs
--- a/PlayerProfile.cs
+++ b/PlayerProfile.cs
@@ -406,8 +406,14 @@ namespace DesertPaintLab
public void ExportWikiRecipes(string file)
{
+ StreamWriter writer = new StreamWriter(file);
+ ExportWikiFormat(writer);
+ }
+
+ public void ExportWikiFormat(TextWriter writer)
+ {
PaintRecipe recipe;
- using (StreamWriter writer = new StreamWriter(file))
+ using (writer)
{
writer.WriteLine("{| class='wikitable sortable' border=\"1\" style=\"background-color:#DEB887;\"");
writer.WriteLine("! Color !! Recipe !! Verified");
@@ -439,7 +445,7 @@ namespace DesertPaintLab
writer.WriteLine("|}");
}
}
-
+
public Reaction FindReaction(Reagent reagent1, Reagent reagent2)
{
return reactions.Find(reagent1, reagent2);
diff --git a/RecipeGenerator.cs b/RecipeGenerator.cs
--- a/RecipeGenerator.cs
+++ b/RecipeGenerator.cs
@@ -57,404 +57,17 @@ namespace DesertPaintLab
public class RecipeGenerator
{
- protected class SearchNode
- {
- //int initialReagentCount;
- uint[] reagents;
- public uint[] Reagents
- {
- get
- {
- return reagents;
- }
- }
- uint INVALID_REAGENT;
- int nextReagentPos;
- public int ReagentCount
- {
- get
- {
- return nextReagentPos;
- }
- }
-
- bool[] reagentInUse;
- List costSortedReagents;
- PaintRecipe testRecipe = null;
- public PaintRecipe TestRecipe
- {
- get
- {
- return testRecipe;
- }
- set
- {
- testRecipe = value;
- }
- }
-
- public int InitialCount { get; private set; }
- public uint CurrentTargetQuantity { get; set; }
- public uint MaxQuantity { get; set; }
- public uint UsedQuantity { get; private set; }
- public uint CatalystCount { get; set; }
-
- uint maxReagents;
- public uint MaxReagents
- {
- get
- {
- return maxReagents;
- }
- set
- {
- maxReagents = value;
- currentWeights = new uint[maxReagents];
- }
- }
-
- uint[] currentWeights;
- public uint[] CurrentWeights
- {
- get
- {
- return currentWeights;
- }
- }
-
- public SearchNode(List costSortedReagents, uint[] reagents)
- {
- this.costSortedReagents = new List(costSortedReagents);
- this.reagents = new uint[costSortedReagents.Count];
- INVALID_REAGENT = (uint)costSortedReagents.Count;
- nextReagentPos = reagents.Length;
- for (int i = this.reagents.Length-1; i >= this.reagents.Length; --i)
- {
- reagents[i] = INVALID_REAGENT;
- }
- for (int i = reagents.Length-1; i >= 0; --i)
- {
- this.reagents[i] = reagents[i];
- if (reagents[i] == INVALID_REAGENT)
- {
- nextReagentPos = i;
- }
- }
- reagentInUse = new bool[costSortedReagents.Count];
- for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
- {
- reagentInUse[reagentIdx] = false;
- }
- foreach (uint reagentIdx in this.reagents)
- {
- if (reagentIdx != INVALID_REAGENT)
- {
- reagentInUse[reagentIdx] = true;
- }
- }
- InitialCount = nextReagentPos;
- MaxReagents = (uint)nextReagentPos; // better set this later!
- UsedQuantity = 0;
- }
-
- // top-level search
- public SearchNode(List costSortedReagents, uint startReagent)
- {
- this.costSortedReagents = new List(costSortedReagents);
- this.reagents = new uint[costSortedReagents.Count];
- INVALID_REAGENT = (uint)costSortedReagents.Count;
- nextReagentPos = 0;
- for (int i = 0; i < reagents.Length; ++i)
- {
- this.reagents[i] = INVALID_REAGENT;
- }
- reagentInUse = new bool[costSortedReagents.Count];
- for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
- {
- reagentInUse[reagentIdx] = false;
- }
- this.reagents[nextReagentPos++] = NextFreeReagent(startReagent);
- InitialCount = 1; // don't iterate up beyond the start reagent
- MaxReagents = 1;
- UsedQuantity = 0;
- }
-
- public SearchNode(List costSortedReagents)
- {
- this.costSortedReagents = costSortedReagents;
- this.reagents = new uint[costSortedReagents.Count];
- INVALID_REAGENT = (uint)costSortedReagents.Count;
- nextReagentPos = 0;
- for (int i = 0; i < reagents.Length; ++i)
- {
- this.reagents[i] = INVALID_REAGENT;
- }
- reagentInUse = new bool[costSortedReagents.Count];
- for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
- {
- reagentInUse[reagentIdx] = false;
- }
- this.reagents[nextReagentPos++] = NextFreeReagent(0);
- InitialCount = 0;
- MaxReagents = 1;
- UsedQuantity = 0;
- }
-
- public Reagent Reagent(int idx)
- {
- return costSortedReagents[(int)reagents[idx]];
- }
-
- public uint LastReagent
- {
- get
- {
- return reagents[nextReagentPos - 1];
- }
- }
-
- public void RemoveLastReagent()
- {
- uint reagentIdx = reagents[nextReagentPos-1];
- ReleaseReagent(reagentIdx);
- if (costSortedReagents[(int)reagentIdx].IsCatalyst)
- {
- --CatalystCount;
- }
- reagents[nextReagentPos-1] = INVALID_REAGENT;
- --nextReagentPos;
- }
-
- public void ReplaceLastReagent(uint reagentIdx)
- {
- uint oldReagentIdx = reagents[nextReagentPos-1];
- ReleaseReagent(oldReagentIdx);
- reagents[nextReagentPos-1] = reagentIdx;
- if (costSortedReagents[(int)oldReagentIdx].IsCatalyst)
- {
- --CatalystCount;
- }
- if (costSortedReagents[(int)reagentIdx].IsCatalyst)
- {
- ++CatalystCount;
- }
- }
+ public enum SearchType {
+ DEPTH_FIRST,
+ BREADTH_FIRST
+ };
- public uint NextFreeReagent(uint startIdx)
- {
- uint idx = startIdx;
- for (; idx < costSortedReagents.Count; ++idx)
- {
- bool inUse = reagentInUse[idx];
- if ((inUse == false) && (costSortedReagents[(int)idx].Enabled))
- {
- //Console.WriteLine("Found free reagent idx {0}", idx);
- reagentInUse[idx] = true;
- return idx;
- }
- }
- //Console.WriteLine("Failed to find free reagent.");
- return (uint)costSortedReagents.Count;
- }
-
- private void ReleaseReagent(uint reagentIdx)
- {
- reagentInUse[reagentIdx] = false;
- }
-
- public bool AddNextReagent()
- {
- bool ok = (nextReagentPos < MaxReagents);
- if (ok)
- {
- uint nextReagent = NextFreeReagent(0);
- reagents[nextReagentPos++] = nextReagent;
- if (costSortedReagents[(int)nextReagent].IsCatalyst)
- {
- ++CatalystCount;
- }
- InitForQuantity(CurrentTargetQuantity);
- }
- return ok;
- }
-
- public void InitForQuantity(uint quantity)
- {
- //System.Console.WriteLine("Target quantity: {0}, reagent count: {1}", quantity, reagents.Count);
- CurrentTargetQuantity = quantity;
- if (CurrentTargetQuantity < (10 + CatalystCount))
- {
- return;
- }
- UsedQuantity = 0;
- uint remainingReagents = ((uint)nextReagentPos - CatalystCount);
- uint remainingWeight = CurrentTargetQuantity - CatalystCount;
- for (int i = 0; i < nextReagentPos; ++i)
- {
- Reagent reagent = Reagent(i);
-
- if (reagent.IsCatalyst)
- {
- currentWeights[i] = 1;
- ++UsedQuantity;
- }
- else
- {
- uint weight = (uint)Math.Min(remainingWeight - (remainingReagents-1), reagent.RecipeMax);
- remainingWeight -= weight;
- currentWeights[i] = weight;
- UsedQuantity += weight;
- }
- --remainingReagents;
- }
- }
-
- public void SetWeight(int idx, uint quantity)
- {
- UsedQuantity -= currentWeights[idx];
- currentWeights[idx] = quantity;
- UsedQuantity += quantity;
- }
-
- public void SaveState(StreamWriter writer)
- {
- writer.WriteLine("---SearchNode---");
- writer.WriteLine("MaxReagents: {0}", MaxReagents);
- writer.WriteLine("Reagents: {0}", nextReagentPos);
- for (int i = 0; i < nextReagentPos; ++i)
- {
- uint idx = reagents[i];
- uint weight = currentWeights[i];
- writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse[idx] ? 1 : 0, weight);
- }
- // pulled from parent: List costSortedReagents;
- // new on construct: PaintRecipe testRecipe = null;
- writer.WriteLine("CurrentTargetQuantity: {0}", CurrentTargetQuantity);
- writer.WriteLine("MaxQuantity: {0}", MaxQuantity);
- writer.WriteLine("UsedQuantity: {0}", UsedQuantity);
- writer.WriteLine("CatalystCount: {0}", CatalystCount);
- writer.WriteLine("InitialCount: {0}", InitialCount);
- writer.WriteLine("---EndNode---");
-
- }
-
- static Regex keyValueRegex = new Regex(@"(\w+)\:\s*(.*)\s*$");
- static Regex reagentPartsRegex = new Regex(@"(?\d+),(?\d+),(?\d+)");
- public bool LoadState(StreamReader reader)
- {
- string line = reader.ReadLine();
- if (!line.Equals("---SearchNode---"))
- {
- return false;
- }
+ public SearchType Mode { get; set; }
- bool success = true;
- Match match;
- while ((line = reader.ReadLine()) != null)
- {
- if (line.Equals("---EndNode---"))
- {
- break;
- }
- match = keyValueRegex.Match(line);
- if (match.Success)
- {
- switch (match.Groups[1].Value)
- {
- case "Reagents":
- {
- //int reagentCount = int.Parse(match.Groups[2].Value);
- for (int i = 0; i < reagents.Length; ++i)
- {
- reagents[i] = INVALID_REAGENT;
- reagentInUse[i] = false;
- }
- nextReagentPos = 0;
- }
- break;
- case "Reagent":
- {
- Match reagentInfo = reagentPartsRegex.Match(match.Groups[2].Value);
- if (reagentInfo.Success)
- {
- uint reagentId = uint.Parse(reagentInfo.Groups["id"].Value);
- int isInUse = int.Parse(reagentInfo.Groups["inUse"].Value);
- uint weight = uint.Parse(reagentInfo.Groups["weight"].Value);
- reagents[nextReagentPos] = reagentId;
- currentWeights[nextReagentPos] = weight;
- if (isInUse != 0)
- {
- if (reagentId != INVALID_REAGENT)
- {
- reagentInUse[reagentId] = true;
- }
- }
- ++nextReagentPos;
- }
- else
- {
- success = false;
- }
- }
- break;
- case "CurrentTargetQuantity":
- {
- uint value = uint.Parse(match.Groups[2].Value);
- CurrentTargetQuantity = value;
- }
- break;
- case "MaxQuantity":
- {
- uint value = uint.Parse(match.Groups[2].Value);
- MaxQuantity = value;
- }
- break;
- case "MaxReagents":
- {
- uint value = uint.Parse(match.Groups[2].Value);
- MaxReagents = value;
- }
- break;
- case "UsedQuantity":
- {
- uint value = uint.Parse(match.Groups[2].Value);
- UsedQuantity = value;
- }
- break;
- case "CatalystCount":
- {
- uint value = uint.Parse(match.Groups[2].Value);
- CatalystCount = value;
- }
- break;
- case "InitialCount":
- {
- int value = int.Parse(match.Groups[2].Value);
- InitialCount = value;
- }
- break;
- default:
- success = false;
- break;
- }
- }
- else
- {
- success = false;
- break;
- }
- }
- return success;
- }
- }
-
- const uint DEFAULT_MAX_QUANTITY = 14; // minimum recipe: 10 base + 4 catalysts
- const uint DEFAULT_MAX_REAGENTS = 5;
-
- //uint maxQuantity; // maximum number of total ingredients
- uint maxReagents; // maximum number of reagents to use in the recipe
- uint fullQuantityDepth; // at or equal this number of reagents, ignore ingredient settings for max quantity
- uint fullQuantity; // The max number of a reagent to use at full quantity
+ public uint MaxQuantity { get; private set; } // maximum number of total ingredients
+ public uint MaxReagents { get; private set; } // maximum number of reagents to use in the recipe
+ public uint FullQuantityDepth { get; private set; } // at or equal this number of reagents, ignore ingredient settings for max quantity
+ public uint FullQuantity { get; private set; } // The max number of a reagent to use at full quantity
ReactionSet reactions;
bool running = false;
@@ -468,15 +81,17 @@ namespace DesertPaintLab
List costSortedReagents = new List();
- ConcurrentQueue searchQueue = new ConcurrentQueue();
+ ConcurrentQueue searchQueue = new ConcurrentQueue();
- int recipeCount = 0;
+ ulong recipeCount = 0;
List generatorThreads = new List();
Object workerLock = new Object();
bool requestCancel = false;
+ StreamWriter log;
+
// events
public event EventHandler Finished;
public event EventHandler Progress;
@@ -484,6 +99,7 @@ namespace DesertPaintLab
public RecipeGenerator(ReactionSet reactions)
{
+ Mode = SearchType.BREADTH_FIRST;
this.reactions = reactions;
foreach (PaintColor color in Palette.Colors)
{
@@ -500,7 +116,7 @@ namespace DesertPaintLab
}
}
- public int RecipeCount
+ public ulong RecipeCount
{
get
{
@@ -516,6 +132,21 @@ namespace DesertPaintLab
}
}
+ public string Log
+ {
+ set
+ {
+ if (value != null)
+ {
+ log = new StreamWriter(value);
+ }
+ else
+ {
+ log = null;
+ }
+ }
+ }
+
private class ReagentCostSort : IComparer
{
public int Compare(Reagent reagent1, Reagent reagent2)
@@ -556,50 +187,63 @@ namespace DesertPaintLab
return;
}
- //this.maxQuantity = maxQuantity;
- this.maxReagents = maxReagents;
- this.fullQuantity = fullQuantity;
- this.fullQuantityDepth = fullQuantityDepth;
+ this.MaxQuantity = maxQuantity;
+ this.MaxReagents = maxReagents;
+ this.FullQuantity = fullQuantity;
+ this.FullQuantityDepth = fullQuantityDepth;
// first, sort reagents by cost.
InitSortedReagents();
- this.maxReagents = (uint)Math.Min(costSortedReagents.Count, this.maxReagents);
totalReagents = (uint)costSortedReagents.Count;
// Pre-populate recipes list with:
// 1) 1-ingredient recipes @ 10db for all enabled ingredients with a count >= 10
// 2) any previously-generated recipes
+ int enabledReagentCount = 0;
PaintRecipe recipe = new PaintRecipe();
recipe.Reactions = reactions;
foreach (Reagent reagent in costSortedReagents)
{
- if (!reagent.IsCatalyst && reagent.RecipeMax >= 10 && reagent.Enabled)
+ if (reagent.Enabled)
{
- recipe.Clear();
- recipe.AddReagent(reagent.Name, 10);
- AddCheapestRecipe(recipe);
+ if (!reagent.IsCatalyst && ((reagent.RecipeMax >= 10) || ((FullQuantityDepth > 0) && (FullQuantity >= 10))))
+ {
+ recipe.Clear();
+ recipe.AddReagent(reagent.Name, 10);
+ AddCheapestRecipe(recipe);
+ }
+ ++enabledReagentCount;
}
}
+ this.MaxReagents = (uint)Math.Min(enabledReagentCount, this.MaxReagents);
while (!searchQueue.IsEmpty)
{
- SearchNode node;
+ RecipeSearchNode node;
searchQueue.TryDequeue(out node);
}
for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
{
if (costSortedReagents[(int)reagentIdx].Enabled)
{
- SearchNode initialNode = new SearchNode(costSortedReagents, reagentIdx);
+ RecipeSearchNode initialNode = new RecipeSearchNode(costSortedReagents, reagentIdx);
+ initialNode.FullQuantity = FullQuantity;
+ initialNode.FullQuantityDepth = FullQuantityDepth;
initialNode.MaxQuantity = maxQuantity;
initialNode.MaxReagents = maxReagents;
searchQueue.Enqueue(initialNode);
}
}
+
+ recipeCount = 0;
+
+ if (log != null)
+ {
+ log.WriteLine("Begin recipe generation: MaxQuantity={0} MaxReagents={1} FullQuantity={2} FullQuantityDepth={3}", MaxQuantity, MaxReagents, FullQuantity, FullQuantityDepth);
+ }
// start worker threads to do the actual work
-
ResumeRecipeGeneration();
}
@@ -613,10 +257,13 @@ namespace DesertPaintLab
running = true;
requestCancel = false;
- //System.Console.WriteLine("Resuming recipe generation: pre-threads={0} reagent count={1} search queue={2}", runningThreads, costSortedReagents.Count, searchQueue.Count);
+ if (log != null)
+ {
+ log.WriteLine("Resuming recipe generation: pre-threads={0} reagent count={1} search queue={2}", runningThreads, costSortedReagents.Count, searchQueue.Count);
+ }
runningThreads = 0; // presumably!
- int threadCount = Math.Min(costSortedReagents.Count, searchQueue.Count);
+ int threadCount = 1; // Math.Min(costSortedReagents.Count, searchQueue.Count);
if (threadCount == 0)
{
if (Finished != null)
@@ -646,11 +293,12 @@ namespace DesertPaintLab
using (StreamWriter writer = new StreamWriter(file, false))
{
- writer.WriteLine("MaxReagents: {0}", maxReagents);
- writer.WriteLine("FullQuantityDepth: {0}", fullQuantityDepth);
- writer.WriteLine("FullQuantity: {0}", fullQuantity);
+ writer.WriteLine("MaxReagents: {0}", MaxReagents);
+ writer.WriteLine("FullQuantityDepth: {0}", FullQuantityDepth);
+ writer.WriteLine("FullQuantity: {0}", FullQuantity);
writer.WriteLine("TotalReagents: {0}", totalReagents);
writer.WriteLine("RecipeCount: {0}", recipeCount);
+ writer.WriteLine("SearchType: {0}", Mode.ToString());
foreach (KeyValuePair pair in recipes)
{
PaintRecipe recipe = pair.Value;
@@ -663,7 +311,7 @@ namespace DesertPaintLab
writer.WriteLine("EndRecipe: {0}", colorName);
}
writer.WriteLine("SearchNodes: {0}", searchQueue.Count);
- foreach (SearchNode node in searchQueue)
+ foreach (RecipeSearchNode node in searchQueue)
{
node.SaveState(writer);
}
@@ -698,19 +346,24 @@ namespace DesertPaintLab
switch(match.Groups["key"].Value)
{
case "MaxReagents":
- maxReagents = uint.Parse(value);
+ MaxReagents = uint.Parse(value);
break;
case "FullQuantityDepth":
- fullQuantityDepth = uint.Parse(value);
+ FullQuantityDepth = uint.Parse(value);
break;
case "FullQuantity":
- fullQuantity = uint.Parse(value);
+ FullQuantity = uint.Parse(value);
break;
case "TotalReagents":
totalReagents = uint.Parse(value);
break;
case "RecipeCount":
- recipeCount = int.Parse(value);
+ if (!ulong.TryParse(value, out recipeCount))
+ {
+ // must have rolled to negative - try as an int and convert
+ int recipeCountInt = int.Parse(value);
+ recipeCount = (ulong)((long)recipeCountInt & 0x00000000ffffffffL);
+ }
break;
case "BeginRecipe":
currentRecipe = new PaintRecipe();
@@ -745,7 +398,11 @@ namespace DesertPaintLab
int nodeCount = int.Parse(match.Groups["value"].Value);
for (int i = 0; i < nodeCount; ++i)
{
- SearchNode node = new SearchNode(costSortedReagents);
+ RecipeSearchNode node = new RecipeSearchNode(costSortedReagents);
+ node.FullQuantity = FullQuantity;
+ node.FullQuantityDepth = FullQuantityDepth;
+ node.MaxReagents = MaxReagents;
+ node.MaxQuantity = MaxQuantity;
success = success && node.LoadState(reader);
if (success)
{
@@ -753,6 +410,9 @@ namespace DesertPaintLab
}
}
break;
+ case "SearchType":
+ Mode = (SearchType)Enum.Parse(typeof(SearchType), match.Groups["value"].Value);
+ break;
default:
success = false;
break;
@@ -770,7 +430,7 @@ namespace DesertPaintLab
private void Generate()
{
- SearchNode node;
+ RecipeSearchNode node;
lock(workerLock)
{
@@ -786,17 +446,38 @@ namespace DesertPaintLab
}
if (ok)
{
- uint targetQuantity = node.MaxQuantity + 1;
- do {
- --targetQuantity;
- node.InitForQuantity(targetQuantity);
- } while (targetQuantity > 10 && (node.CurrentTargetQuantity != node.UsedQuantity));
-
- while ((ok = Iterate(node)) && !requestCancel)
+ if (Mode == SearchType.DEPTH_FIRST)
{
- if (Progress != null)
+ uint targetQuantity = (node.ReagentCount <= FullQuantityDepth) ? ((uint)node.ReagentCount * FullQuantity) : node.MaxQuantity + 1;
+ do {
+ --targetQuantity;
+ node.InitForQuantity(targetQuantity);
+ } while (targetQuantity > 10 && (node.CurrentTargetQuantity != node.UsedQuantity));
+
+ while ((ok = IterateDepthFirst(node)) && !requestCancel)
{
- Progress(this, null);
+ if (Progress != null)
+ {
+ Progress(this, null);
+ }
+ }
+ }
+ else
+ {
+ // breadth-first search
+ uint targetQuantity = 9;
+ uint quantityLimit = (node.ReagentCount <= FullQuantityDepth) ? (FullQuantity * (uint)node.ReagentCount) : node.MaxQuantity;
+ do {
+ ++targetQuantity;
+ node.InitForQuantity(targetQuantity);
+ } while ((targetQuantity <= quantityLimit) && (node.CurrentTargetQuantity != node.UsedQuantity));
+
+ while ((ok = IterateBreadthFirst(node)) && !requestCancel)
+ {
+ if (Progress != null)
+ {
+ Progress(this, null);
+ }
}
}
if (ok)
@@ -882,8 +563,10 @@ namespace DesertPaintLab
//}
}
- private bool Iterate(SearchNode node)
+ private bool IterateDepthFirst(RecipeSearchNode node)
{
+ TestCurrentRecipe(node);
+
// pick recipe quantities at current recipe ingredients/size
if (NextRecipe(node))
{
@@ -897,7 +580,7 @@ namespace DesertPaintLab
if (NextRecipeSize(node))
{
- //System.Console.WriteLine("Found next recipee size {0}", node.CurrentTargetQuantity);
+ //System.Console.WriteLine("Found next recipe size {0}", node.CurrentTargetQuantity);
return true;
}
@@ -950,9 +633,146 @@ namespace DesertPaintLab
return true;
}
- private bool NextRecipe(SearchNode node)
+ private bool IterateBreadthFirst(RecipeSearchNode node)
{
- // First, run the current recipe
+ // pick recipe quantities at current recipe ingredients/size
+ TestCurrentRecipe(node);
+ lock(workerLock)
+ {
+ ++recipeCount;
+ }
+
+ // search all quantities of current recipe
+ if (NextRecipe(node))
+ {
+ //System.Console.WriteLine("Found next recipe at size {0} qty {1}", node.ReagentCount, node.CurrentTargetQuantity);
+ return true;
+ }
+
+ // Try next quantity
+ uint newQuantity;
+ uint quantityLimit = ((uint)node.ReagentCount <= FullQuantityDepth) ? ((uint)node.ReagentCount * FullQuantity) : node.MaxQuantity;
+ do {
+ newQuantity = node.CurrentTargetQuantity + 1;
+ //Console.WriteLine("Try quantity {0}", newQuantity);
+ if (newQuantity <= quantityLimit)
+ {
+ node.InitForQuantity(newQuantity);
+ if (node.CurrentTargetQuantity <= node.UsedQuantity)
+ {
+ if (log != null) { lock(log) { log.WriteLine("Update quantity to {0}", node.CurrentTargetQuantity); } }
+ return true;
+ }
+ }
+ } while (newQuantity < quantityLimit);
+
+ // search all variants at this depth of recipe
+ // increase recipe depth
+
+ // next reagent in last position
+ // if at end, pop reagent
+ //Console.WriteLine("Finding new recipe after quantity {0}/{1} used {2}", newQuantity, node.MaxQuantity, node.UsedQuantity);
+ node.InitForQuantity(10+node.CatalystCount); // reset quantity
+ int currentDepth = node.ReagentCount;
+ bool recipeFound = false;
+ uint nextReagent;
+ do {
+ //Console.WriteLine("Current depth: {0}/{1}", currentDepth, node.MaxReagents);
+ do {
+ recipeFound = false;
+ // back out until we find a node that can be incremented
+ if (currentDepth > node.InitialCount)
+ {
+ while (node.ReagentCount > node.InitialCount)
+ {
+ if (node.LastReagent < (totalReagents - 1))
+ {
+ nextReagent = node.NextFreeReagent(node.LastReagent);
+ if (nextReagent < totalReagents)
+ {
+ //Console.WriteLine("Replace last reagent with {0}", nextReagent);
+ node.ReplaceLastReagent(nextReagent);
+ break;
+ }
+ else
+ {
+ // shouldn't happen
+ //Console.WriteLine("No available reagents at depth {0}!", node.ReagentCount);
+ node.RemoveLastReagent();
+ if (node.ReagentCount == node.InitialCount)
+ {
+ // just popped the last reagent at the top level
+ ++currentDepth;
+ if (log != null) { lock(log) { log.WriteLine("Increased depth to {0}/{1}", currentDepth, node.MaxReagents); } }
+ }
+ }
+ }
+ else
+ {
+ //Console.WriteLine("Pop last reagent");
+ node.RemoveLastReagent();
+ if (node.ReagentCount == node.InitialCount)
+ {
+ // just popped the last reagent at the top level
+ ++currentDepth;
+ if (log != null) { lock(log) { log.WriteLine("Increased depth to {0}/{1} [pop last reagent at top level]", currentDepth, node.MaxReagents); } }
+ }
+ }
+ }
+ // fill in the nodes up to the current depth
+ if (node.ReagentCount >= node.InitialCount)
+ {
+ recipeFound = true;
+ while (node.ReagentCount < currentDepth)
+ {
+ if (! node.AddNextReagent())
+ {
+ if (log != null) { lock(log) { log.WriteLine("Failed to reagent {0}/{1}", node.ReagentCount+1, currentDepth); } }
+ recipeFound = false;
+ }
+ }
+ }
+ }
+ //Console.WriteLine("Catalysts: {0} Reagents: {1} Initial: {2}", node.CatalystCount, node.ReagentCount, node.InitialCount);
+ } while ((node.CatalystCount >= node.ReagentCount) && (node.ReagentCount >= node.InitialCount)); // make sure to skip all-catalyst combinations
+ if (recipeFound)
+ {
+ break;
+ }
+ else
+ {
+ ++currentDepth;
+ if (log != null) { lock(log) { log.WriteLine("Increased depth to {0}/{1} [no recipe]", currentDepth, node.MaxReagents); } }
+ }
+ } while (currentDepth <= node.MaxReagents);
+ if (recipeFound)
+ {
+ node.InitForQuantity(10+node.CatalystCount); // minimum quantity for this recipe
+ if (node.TestRecipe == null)
+ {
+ node.TestRecipe = new PaintRecipe();
+ node.TestRecipe.Reactions = reactions;
+ }
+ node.TestRecipe.Clear();
+ for (int i = 0; i < node.ReagentCount; ++i)
+ {
+ node.TestRecipe.AddReagent(node.Reagent(i).Name, node.CurrentWeights[i]);
+ }
+ if (log != null) {
+ string combo = "";
+ foreach (PaintRecipe.RecipeIngredient ingr in node.TestRecipe.Ingredients)
+ {
+ combo += " " + ingr.name;
+ }
+ lock(log) { log.WriteLine("New ingredients: " + combo); }
+ }
+ }
+
+ return recipeFound;
+ }
+
+ private void TestCurrentRecipe(RecipeSearchNode node)
+ {
if (node.TestRecipe == null)
{
node.TestRecipe = new PaintRecipe();
@@ -964,12 +784,17 @@ namespace DesertPaintLab
node.TestRecipe.AddReagent(node.Reagent(i).Name, node.CurrentWeights[i]);
}
AddCheapestRecipe(node.TestRecipe);
-
+ //if (log != null) { lock(log) { log.WriteLine("Tested recipe: {0}", node.TestRecipe); } }
+ }
+
+ private bool NextRecipe(RecipeSearchNode node)
+ {
// check for the next recipe
uint remainingWeight = node.CurrentTargetQuantity - node.CatalystCount;
if (remainingWeight < 10)
{
// not possible to make a valid recipe
+ Console.WriteLine("Insufficient remaining weight");
return false;
}
//uint remainingReagents = (uint)node.Reagents.Count - node.CatalystCount;
@@ -991,7 +816,7 @@ namespace DesertPaintLab
{
--reagentsBelow;
Reagent reagent = node.Reagent(j);
- uint allocated = (uint)Math.Min(reagent.IsCatalyst ? 1 : (depth <= fullQuantityDepth ? fullQuantity : reagent.RecipeMax), weightToConsume - reagentsBelow);
+ uint allocated = (uint)Math.Min(reagent.IsCatalyst ? 1 : (depth <= FullQuantityDepth ? FullQuantity : reagent.RecipeMax), weightToConsume - reagentsBelow);
if (allocated > 100)
{
Console.WriteLine("ACK: allocated = {0}", allocated);
@@ -1004,7 +829,7 @@ namespace DesertPaintLab
else
{
Reagent reagent = node.Reagent(i);
- spaceBelow += (reagent.IsCatalyst ? 1 : (depth <= fullQuantityDepth ? fullQuantity : reagent.RecipeMax));
+ spaceBelow += (reagent.IsCatalyst ? 1 : (depth <= FullQuantityDepth ? FullQuantity : reagent.RecipeMax));
weightToConsume += currentWeight;
++reagentsBelow;
}
@@ -1027,7 +852,7 @@ namespace DesertPaintLab
return (weightToConsume == 0);
}
- private bool NextRecipeSize(SearchNode node)
+ private bool NextRecipeSize(RecipeSearchNode node)
{
uint newQuantity = node.CurrentTargetQuantity - 1;
if (newQuantity < (10 + node.CatalystCount))
diff --git a/RecipeGeneratorWindow.cs b/RecipeGeneratorWindow.cs
--- a/RecipeGeneratorWindow.cs
+++ b/RecipeGeneratorWindow.cs
@@ -21,6 +21,7 @@
*/
using System;
+using System.IO;
using System.Collections.Generic;
using System.Collections.Concurrent;
@@ -61,6 +62,9 @@ namespace DesertPaintLab
ConcurrentQueue pendingNewRecipes = new ConcurrentQueue();
+ Gtk.ListStore reagentListStore;
+ // end reagent view
+
public RecipeGeneratorWindow(PlayerProfile profile) : base(Gtk.WindowType.Toplevel)
{
this.profile = profile;
@@ -73,6 +77,7 @@ namespace DesertPaintLab
fullQuantityDepthSpinButton.SetRange(0, ReagentManager.Names.Count);
maxIngredientsSpinButton.SetRange(0, ReagentManager.Names.Count);
+
Gtk.TreeViewColumn recipeColorColumn = new Gtk.TreeViewColumn();
Gtk.CellRendererText recipeColumnCell = new Gtk.CellRendererText();
recipeColorColumn.PackStart(recipeColumnCell, true);
@@ -88,6 +93,10 @@ namespace DesertPaintLab
recipeList.Selection.Changed += OnColorSelected;
+ recipeIngredientsView.AppendColumn("Quantity", new Gtk.CellRendererText(), "text", 0);
+ recipeIngredientsView.AppendColumn("Ingredient", new Gtk.CellRendererText(), "text", 1);
+ recipeIngredientsView.Model = new Gtk.ListStore(typeof(string), typeof(string));
+
profile.LoadRecipes();
// init UI
@@ -120,8 +129,14 @@ namespace DesertPaintLab
beginButton.Label = "Restart";
stopResumeButton.Label = "Resume";
stopResumeButton.Sensitive = true;
+
+ maxRecipeSpinButton.Value = Math.Max(generator.MaxQuantity, 14); //
+ fullQuantitySpinButton.Value = generator.FullQuantity; // TODO: read/save profile info
+ fullQuantityDepthSpinButton.Value = generator.FullQuantityDepth; // TODO: read/save profile info
+ maxIngredientsSpinButton.Value = generator.MaxReagents;
}
}
+ generator.Log = System.IO.Path.Combine(profile.Directory, "dp_log.txt");
countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount, Palette.Count);
Destroyed += OnDestroyed;
@@ -129,6 +144,65 @@ namespace DesertPaintLab
notifyFinished = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleFinished));
notifyProgress = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleProgress));
notifyNewRecipe = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleNewRecipe));
+
+ // initialize reagent list
+
+ // Add the columns to the TreeView
+ Gtk.TreeViewColumn reagentEnabledColumn = new Gtk.TreeViewColumn ();
+ reagentEnabledColumn.Title = "Enabled";
+ Gtk.CellRendererToggle reagentEnabledCell = new Gtk.CellRendererToggle ();
+ reagentEnabledCell.Activatable = true;
+ reagentEnabledCell.Sensitive = true;
+ reagentEnabledCell.Mode = Gtk.CellRendererMode.Activatable;
+ reagentEnabledCell.Toggled += new Gtk.ToggledHandler(OnReagentEnableToggled);
+ reagentEnabledColumn.PackStart (reagentEnabledCell, true);
+ //reagentEnabledColumn.AddAttribute(reagentEnabledCell, "active", 0);
+
+ Gtk.TreeViewColumn reagentNameColumn = new Gtk.TreeViewColumn ();
+ reagentNameColumn.Title = "Ingredient";
+ Gtk.CellRendererText reagentNameCell = new Gtk.CellRendererText ();
+ reagentNameColumn.PackStart (reagentNameCell, true);
+ reagentNameColumn.AddAttribute(reagentNameCell, "text", 1);
+ reagentNameColumn.Expand = true;
+
+ Gtk.TreeViewColumn reagentCostColumn = new Gtk.TreeViewColumn ();
+ reagentCostColumn.Title = "Cost";
+ Gtk.CellRendererText reagentCostCell = new Gtk.CellRendererText ();
+ reagentCostCell.Edited += OnReagentCostChanged;
+ reagentCostCell.Editable = true;
+ reagentCostCell.Sensitive = true;
+ reagentCostColumn.PackStart (reagentCostCell, true);
+ //reagentCostColumn.AddAttribute(reagentCostCell, "text", 0);
+
+ Gtk.TreeViewColumn reagentMaxColumn = new Gtk.TreeViewColumn ();
+ reagentMaxColumn.Title = "Max";
+ Gtk.CellRendererText reagentMaxCell = new Gtk.CellRendererText ();
+ reagentMaxCell.Edited += OnReagentQuantityChanged;
+ reagentMaxCell.Editable = true;
+ reagentMaxCell.Sensitive = true;
+ reagentMaxColumn.PackStart (reagentMaxCell, true);
+ //reagentMaxColumn.AddAttribute(reagentMaxCell, "text", 0);
+
+ reagentListStore = new Gtk.ListStore(typeof(Reagent), typeof(string), typeof(Reagent), typeof(Reagent));
+ foreach (string reagentName in ReagentManager.Names)
+ {
+ Reagent reagent = ReagentManager.GetReagent(reagentName);
+ reagentListStore.AppendValues(reagent, reagentName); // , reagent, reagent);
+ }
+
+ reagentEnabledColumn.SetCellDataFunc (reagentEnabledCell, new Gtk.TreeCellDataFunc (RenderReagentToggle));
+ reagentCostColumn.SetCellDataFunc (reagentCostCell, new Gtk.TreeCellDataFunc (RenderReagentCost));
+ reagentMaxColumn.SetCellDataFunc (reagentMaxCell, new Gtk.TreeCellDataFunc (RenderReagentQuantity));
+
+ // Assign the model to the TreeView
+ reagentListView.Model = reagentListStore;
+
+ reagentListView.AppendColumn(reagentEnabledColumn);
+ reagentListView.AppendColumn(reagentNameColumn);
+ reagentListView.AppendColumn(reagentCostColumn);
+ reagentListView.AppendColumn(reagentMaxColumn);
+
+ ShowAll();
}
protected void OnMaxIngredientsChanged(object sender, EventArgs e)
@@ -165,6 +239,7 @@ namespace DesertPaintLab
stopResumeButton.Sensitive = true;
fullQuantitySpinButton.Sensitive = false;
fullQuantityDepthSpinButton.Sensitive = false;
+ reagentListView.Sensitive = false;
countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount, Palette.Count);
@@ -212,13 +287,22 @@ namespace DesertPaintLab
// Resume previous run
ExportToWikiAction.Sensitive = false;
IngredientsAction.Sensitive = false;
+ reagentListView.Sensitive = false;
+ maxIngredientsSpinButton.Sensitive = false;
+ maxRecipeSpinButton.Sensitive = false;
+ beginButton.Sensitive = false;
+ stopResumeButton.Sensitive = true;
+ fullQuantitySpinButton.Sensitive = false;
+ fullQuantityDepthSpinButton.Sensitive = false;
+ reagentListView.Sensitive = false;
+
lastProgressUpdate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
lastStatusUpdate = lastProgressUpdate;
lastProfileSave = lastProgressUpdate;
lastCheckpoint = lastProgressUpdate;
canceling = false;
- pauseForCheckpoint = false;
+ pauseForCheckpoint = false;
running = true;
stopResumeButton.Label = "Pause";
@@ -247,6 +331,7 @@ namespace DesertPaintLab
maxRecipeSpinButton.Sensitive = true;
fullQuantitySpinButton.Sensitive = true;
fullQuantityDepthSpinButton.Sensitive = true;
+ reagentListView.Sensitive = false;
//generator = null; // don't. Hang on to generator for resume.
profile.SaveRecipes();
if (canceling)
@@ -366,19 +451,15 @@ namespace DesertPaintLab
PaintRecipe recipe;
if (profile.Recipes.TryGetValue(colorName, out recipe))
{
- foreach (Gtk.Widget child in recipeListBox.AllChildren)
- {
- recipeListBox.Remove(child);
- }
+ Gtk.ListStore store = (Gtk.ListStore)recipeIngredientsView.Model;
+ store.Clear();
if (recipe.CheckMissingReactions(ref missingReactions))
{
statusLabel.Text = "WARNING: This recipe includes reactions that have not yet been recorded.";
}
foreach (PaintRecipe.RecipeIngredient ingredient in recipe.Ingredients)
{
- Gtk.Label label = new Gtk.Label(ingredient.quantity.ToString() + " " + ingredient.name);
- recipeListBox.PackStart(label);
- label.Show();
+ store.AppendValues(ingredient.quantity.ToString(), ingredient.name);
}
}
paintSwatch.Color = recipe.ReactedColor;
@@ -421,6 +502,107 @@ namespace DesertPaintLab
generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
}
}
+
+ // Reagent view handling
+ private void RenderReagentToggle (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
+ {
+ Reagent reagent = (Reagent) model.GetValue (iter, 0);
+ Gtk.CellRendererToggle toggle = (cell as Gtk.CellRendererToggle);
+ toggle.Active = reagent.Enabled;
+ toggle.Activatable = !reagent.IsCatalyst;
+ }
+ private void RenderReagentCost (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
+ {
+ Reagent reagent = (Reagent) model.GetValue (iter, 0);
+ (cell as Gtk.CellRendererText).Text = reagent.Cost.ToString();
+ }
+ private void RenderReagentQuantity (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
+ {
+ Reagent reagent = (Reagent) model.GetValue (iter, 0);
+ (cell as Gtk.CellRendererText).Text = reagent.RecipeMax.ToString();
+ }
+
+ private void OnReagentCostChanged(object o, Gtk.EditedArgs args)
+ {
+ uint newCost;
+ if (uint.TryParse(args.NewText, out newCost))
+ {
+ Gtk.TreeIter iter;
+ reagentListStore.GetIter (out iter, new Gtk.TreePath (args.Path));
+
+ Reagent reagent = (Reagent) reagentListStore.GetValue (iter, 0);
+ if (reagent.Cost != newCost)
+ {
+ reagent.Cost = newCost;
+ SaveReagentSettings();
+ }
+ }
+ }
+
+ private void OnReagentQuantityChanged(object o, Gtk.EditedArgs args)
+ {
+ uint newMax;
+ if (uint.TryParse(args.NewText, out newMax))
+ {
+ Gtk.TreeIter iter;
+ reagentListStore.GetIter (out iter, new Gtk.TreePath (args.Path));
+
+ Reagent reagent = (Reagent) reagentListStore.GetValue (iter, 0);
+ if (reagent.RecipeMax != newMax)
+ {
+ reagent.RecipeMax = newMax;
+ SaveReagentSettings();
+ }
+ }
+ }
+
+ private void OnReagentEnableToggled(object o, Gtk.ToggledArgs args)
+ {
+ Gtk.CellRendererToggle btn = (Gtk.CellRendererToggle)o;
+ Gtk.TreeIter iter;
+ reagentListStore.GetIter (out iter, new Gtk.TreePath (args.Path));
+
+ Reagent reagent = (Reagent) reagentListStore.GetValue (iter, 0);
+ if (btn.Active != reagent.Enabled)
+ {
+ reagent.Enabled = btn.Active;
+ SaveReagentSettings();
+ }
+ }
+
+ private void SaveReagentSettings()
+ {
+ // save out state
+ ReagentManager.SaveProfileReagents(profile.ReagentFile);
+ }
+
+ protected void OnCopyRecipeToClipboard(object sender, EventArgs e)
+ {
+ Gtk.TreeModel model;
+ Gtk.TreeIter iter;
+ Gtk.Clipboard clipboard = recipeIngredientsView.GetClipboard(Gdk.Selection.Clipboard);
+
+ Gtk.TreeSelection selection = recipeList.Selection;
+ if ((selection != null) && selection.GetSelected(out model, out iter))
+ {
+ string colorName = (string)colorStore.GetValue(iter, 0);
+ PaintRecipe recipe;
+ if (profile.Recipes.TryGetValue(colorName, out recipe))
+ {
+ clipboard.Text = recipe.ToString();
+ }
+ }
+ }
+
+ protected void OnCopyRecipeListToClipboard(object sender, EventArgs e)
+ {
+ Gtk.Clipboard clipboard = recipeList.GetClipboard(Gdk.Selection.Clipboard);
+
+ StringWriter writer = new StringWriter();
+ profile.ExportWikiFormat(writer);
+
+ clipboard.Text = writer.ToString();
+ }
}
}
diff --git a/RecipeSearchNode.cs b/RecipeSearchNode.cs
new file mode 100644
--- /dev/null
+++ b/RecipeSearchNode.cs
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2015, Jason Maltzen
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+
+namespace DesertPaintLab
+{
+ public class RecipeSearchNode
+ {
+ //int initialReagentCount;
+ uint[] reagents;
+ public uint[] Reagents
+ {
+ get
+ {
+ return reagents;
+ }
+ }
+ uint INVALID_REAGENT;
+ int nextReagentPos;
+ public int ReagentCount
+ {
+ get
+ {
+ return nextReagentPos;
+ }
+ }
+
+ bool[] reagentInUse;
+ List costSortedReagents;
+ PaintRecipe testRecipe = null;
+ public PaintRecipe TestRecipe
+ {
+ get
+ {
+ return testRecipe;
+ }
+ set
+ {
+ testRecipe = value;
+ }
+ }
+
+ public int InitialCount { get; private set; }
+ public uint CurrentTargetQuantity { get; set; }
+ public uint MaxQuantity { get; set; }
+ public uint UsedQuantity { get; private set; }
+ public uint CatalystCount { get; set; }
+ public uint FullQuantityDepth { get; set; }
+ public uint FullQuantity { get; set; }
+
+ uint maxReagents;
+ public uint MaxReagents
+ {
+ get
+ {
+ return maxReagents;
+ }
+ set
+ {
+ maxReagents = value;
+ currentWeights = new uint[maxReagents];
+ }
+ }
+
+ uint[] currentWeights;
+ public uint[] CurrentWeights
+ {
+ get
+ {
+ return currentWeights;
+ }
+ }
+
+ public RecipeSearchNode(List costSortedReagents, uint[] reagents)
+ {
+ this.costSortedReagents = new List(costSortedReagents);
+ this.reagents = new uint[costSortedReagents.Count];
+ INVALID_REAGENT = (uint)costSortedReagents.Count;
+ nextReagentPos = reagents.Length;
+ for (int i = this.reagents.Length-1; i >= this.reagents.Length; --i)
+ {
+ reagents[i] = INVALID_REAGENT;
+ }
+ for (int i = reagents.Length-1; i >= 0; --i)
+ {
+ this.reagents[i] = reagents[i];
+ if (reagents[i] == INVALID_REAGENT)
+ {
+ nextReagentPos = i;
+ }
+ }
+ reagentInUse = new bool[costSortedReagents.Count];
+ for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
+ {
+ reagentInUse[reagentIdx] = false;
+ }
+ foreach (uint reagentIdx in this.reagents)
+ {
+ if (reagentIdx != INVALID_REAGENT)
+ {
+ reagentInUse[reagentIdx] = true;
+ }
+ }
+ InitialCount = nextReagentPos;
+ MaxReagents = (uint)nextReagentPos; // better set this later!
+ UsedQuantity = 0;
+ }
+
+ // top-level search
+ public RecipeSearchNode(List costSortedReagents, uint startReagent)
+ {
+ this.costSortedReagents = new List(costSortedReagents);
+ this.reagents = new uint[costSortedReagents.Count];
+ INVALID_REAGENT = (uint)costSortedReagents.Count;
+ nextReagentPos = 0;
+ for (int i = 0; i < reagents.Length; ++i)
+ {
+ this.reagents[i] = INVALID_REAGENT;
+ }
+ reagentInUse = new bool[costSortedReagents.Count];
+ for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
+ {
+ reagentInUse[reagentIdx] = false;
+ }
+ this.reagents[nextReagentPos++] = NextFreeReagent(startReagent);
+ //Console.WriteLine("Added reagent {0} at pos {1}", this.reagents[nextReagentPos-1], nextReagentPos-1);
+ InitialCount = 1; // don't iterate up beyond the start reagent
+ MaxReagents = 1;
+ UsedQuantity = 0;
+ }
+
+ public RecipeSearchNode(List costSortedReagents)
+ {
+ this.costSortedReagents = costSortedReagents;
+ this.reagents = new uint[costSortedReagents.Count];
+ INVALID_REAGENT = (uint)costSortedReagents.Count;
+ nextReagentPos = 0;
+ for (int i = 0; i < reagents.Length; ++i)
+ {
+ this.reagents[i] = INVALID_REAGENT;
+ }
+ reagentInUse = new bool[costSortedReagents.Count];
+ for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
+ {
+ reagentInUse[reagentIdx] = false;
+ }
+ this.reagents[nextReagentPos++] = NextFreeReagent(0);
+ InitialCount = 0;
+ MaxReagents = 1;
+ UsedQuantity = 0;
+ }
+
+ public Reagent Reagent(int idx)
+ {
+ return costSortedReagents[(int)reagents[idx]];
+ }
+
+ public uint LastReagent
+ {
+ get
+ {
+ return reagents[nextReagentPos - 1];
+ }
+ }
+
+ public void RemoveLastReagent()
+ {
+ uint reagentIdx = reagents[nextReagentPos-1];
+ ReleaseReagent(reagentIdx);
+ if (costSortedReagents[(int)reagentIdx].IsCatalyst)
+ {
+ --CatalystCount;
+ }
+ reagents[nextReagentPos-1] = INVALID_REAGENT;
+ --nextReagentPos;
+ }
+
+ public void ReplaceLastReagent(uint reagentIdx)
+ {
+ uint oldReagentIdx = reagents[nextReagentPos-1];
+ ReleaseReagent(oldReagentIdx);
+ reagents[nextReagentPos-1] = reagentIdx;
+ if (costSortedReagents[(int)oldReagentIdx].IsCatalyst)
+ {
+ --CatalystCount;
+ }
+ if (costSortedReagents[(int)reagentIdx].IsCatalyst)
+ {
+ ++CatalystCount;
+ }
+ }
+
+ public uint NextFreeReagent(uint startIdx)
+ {
+ uint idx = startIdx;
+ for (; idx < costSortedReagents.Count; ++idx)
+ {
+ bool inUse = reagentInUse[idx];
+ if ((inUse == false) && (costSortedReagents[(int)idx].Enabled))
+ {
+ //Console.WriteLine("Found free reagent idx {0}", idx);
+ reagentInUse[idx] = true;
+ return idx;
+ }
+ }
+ //Console.WriteLine("Failed to find free reagent.");
+ return (uint)costSortedReagents.Count;
+ }
+
+ private void ReleaseReagent(uint reagentIdx)
+ {
+ reagentInUse[reagentIdx] = false;
+ }
+
+ public bool AddNextReagent()
+ {
+ bool ok = (nextReagentPos < MaxReagents);
+ if (ok)
+ {
+ uint nextReagent = NextFreeReagent(0);
+ reagents[nextReagentPos++] = nextReagent;
+ if (costSortedReagents[(int)nextReagent].IsCatalyst)
+ {
+ ++CatalystCount;
+ }
+ InitForQuantity(CurrentTargetQuantity);
+ }
+ return ok;
+ }
+
+ public void InitForQuantity(uint quantity)
+ {
+ //System.Console.WriteLine("Init for quantity: {0}, reagent count: {1} ({2} catalysts)", quantity, ReagentCount, CatalystCount);
+ CurrentTargetQuantity = quantity;
+ if (CurrentTargetQuantity < (10 + CatalystCount))
+ {
+ // invalid quantity
+ return;
+ }
+ UsedQuantity = 0;
+ uint remainingReagents = ((uint)nextReagentPos - CatalystCount);
+ uint remainingWeight = CurrentTargetQuantity - CatalystCount;
+ for (int i = 0; i < nextReagentPos; ++i)
+ {
+ Reagent reagent = Reagent(i);
+
+ if (reagent.IsCatalyst)
+ {
+ //Console.WriteLine("Init catalyst {0} weight 1", reagent.Name);
+ currentWeights[i] = 1;
+ ++UsedQuantity;
+ }
+ else
+ {
+ uint reagentMaxWeight = reagent.RecipeMax;
+ if (ReagentCount <= FullQuantityDepth)
+ {
+ reagentMaxWeight = Math.Max(FullQuantity, reagentMaxWeight);
+ }
+ uint weight = (uint)Math.Min(remainingWeight - (remainingReagents-1), reagentMaxWeight);
+ //Console.WriteLine("Init reagent {0} weight {1}", reagent.Name, weight);
+ remainingWeight -= weight;
+ currentWeights[i] = weight;
+ UsedQuantity += weight;
+ }
+ --remainingReagents;
+ }
+ }
+
+ public void SetWeight(int idx, uint quantity)
+ {
+ UsedQuantity -= currentWeights[idx];
+ currentWeights[idx] = quantity;
+ UsedQuantity += quantity;
+ }
+
+ public void SaveState(StreamWriter writer)
+ {
+ writer.WriteLine("---SearchNode---");
+ writer.WriteLine("MaxReagents: {0}", MaxReagents);
+ writer.WriteLine("Reagents: {0}", nextReagentPos);
+ for (int i = 0; i < nextReagentPos; ++i)
+ {
+ uint idx = reagents[i];
+ uint weight = currentWeights[i];
+ writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse[idx] ? 1 : 0, weight);
+ }
+ // pulled from parent: List costSortedReagents;
+ // new on construct: PaintRecipe testRecipe = null;
+ writer.WriteLine("CurrentTargetQuantity: {0}", CurrentTargetQuantity);
+ writer.WriteLine("MaxQuantity: {0}", MaxQuantity);
+ writer.WriteLine("UsedQuantity: {0}", UsedQuantity);
+ writer.WriteLine("CatalystCount: {0}", CatalystCount);
+ writer.WriteLine("InitialCount: {0}", InitialCount);
+ writer.WriteLine("FullQuantity: {0}", FullQuantity);
+ writer.WriteLine("FullQuantityDepth: {0}", FullQuantityDepth);
+ writer.WriteLine("---EndNode---");
+
+ }
+
+ static Regex keyValueRegex = new Regex(@"(\w+)\:\s*(.*)\s*$");
+ static Regex reagentPartsRegex = new Regex(@"(?\d+),(?\d+),(?\d+)");
+ public bool LoadState(StreamReader reader)
+ {
+ string line = reader.ReadLine();
+ if (!line.Equals("---SearchNode---"))
+ {
+ return false;
+ }
+
+ bool success = true;
+ Match match;
+ while ((line = reader.ReadLine()) != null)
+ {
+ if (line.Equals("---EndNode---"))
+ {
+ break;
+ }
+ match = keyValueRegex.Match(line);
+ if (match.Success)
+ {
+ switch (match.Groups[1].Value)
+ {
+ case "Reagents":
+ {
+ //int reagentCount = int.Parse(match.Groups[2].Value);
+ for (int i = 0; i < reagents.Length; ++i)
+ {
+ reagents[i] = INVALID_REAGENT;
+ reagentInUse[i] = false;
+ }
+ nextReagentPos = 0;
+ }
+ break;
+ case "Reagent":
+ {
+ Match reagentInfo = reagentPartsRegex.Match(match.Groups[2].Value);
+ if (reagentInfo.Success)
+ {
+ uint reagentId = uint.Parse(reagentInfo.Groups["id"].Value);
+ int isInUse = int.Parse(reagentInfo.Groups["inUse"].Value);
+ uint weight = uint.Parse(reagentInfo.Groups["weight"].Value);
+ reagents[nextReagentPos] = reagentId;
+ currentWeights[nextReagentPos] = weight;
+ if (isInUse != 0)
+ {
+ if (reagentId != INVALID_REAGENT)
+ {
+ reagentInUse[reagentId] = true;
+ }
+ }
+ ++nextReagentPos;
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ break;
+ case "CurrentTargetQuantity":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ CurrentTargetQuantity = value;
+ }
+ break;
+ case "MaxQuantity":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ MaxQuantity = value;
+ }
+ break;
+ case "MaxReagents":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ MaxReagents = value;
+ }
+ break;
+ case "UsedQuantity":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ UsedQuantity = value;
+ }
+ break;
+ case "CatalystCount":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ CatalystCount = value;
+ }
+ break;
+ case "InitialCount":
+ {
+ int value = int.Parse(match.Groups[2].Value);
+ InitialCount = value;
+ }
+ break;
+ case "FullQuantity":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ FullQuantity = value;
+ }
+ break;
+ case "FullQuantityDepth":
+ {
+ uint value = uint.Parse(match.Groups[2].Value);
+ FullQuantityDepth = value;
+ }
+ break;
+ default:
+ success = false;
+ break;
+ }
+ }
+ else
+ {
+ success = false;
+ break;
+ }
+ }
+ return success;
+ }
+ }
+}
+
diff --git a/bin/Debug/DesertPaintLab/colors.txt b/bin/Debug/DesertPaintLab/colors.txt
deleted file mode 100644
--- a/bin/Debug/DesertPaintLab/colors.txt
+++ /dev/null
@@ -1,142 +0,0 @@
-#F0F8FF AliceBlue
-#FAEBD7 AntiqueWhite
-#00FFFF Aqua
-#7FFFD4 Aquamarine
-#F0FFFF Azure
-#F5F5DC Beige
-#FFE4C4 Bisque
-#010101 Black
-#FFEBCD BlanchedAlmond
-#0000FF Blue
-#8A2BE2 BlueViolet
-#A52A2A Brown
-#DEB887 Burlywood
-#5F9EA0 CadetBlue
-#E07020 Carrot
-#7FFF00 Chartreuse
-#D2691E Chocolate
-#FF7F50 Coral
-#6495ED CornflowerBlue
-#FFF8DC Cornsilk
-#DC143C Crimson
-#00008B DarkBlue
-#008B8B DarkCyan
-#B8860B DarkGoldenrod
-#A9A9A9 DarkGray
-#006400 DarkGreen
-#BDB76B DarkKhaki
-#8B008B DarkMagenta
-#556B2F DarkOliveGreen
-#FF8C00 DarkOrange
-#9932CC DarkOrchid
-#8B0000 DarkRed
-#E9967A DarkSalmon
-#8FBC8F DarkSeaGreen
-#483D8B DarkSlateBlue
-#2F4F4F DarkSlateGray
-#00CED1 DarkTurquoise
-#9400D3 DarkViolet
-#FF1493 DeepPink
-#00BFFF DeepSkyBlue
-#696969 DimGray
-#1E90FF DodgerBlue
-#D19275 Feldspar
-#B22222 FireBrick
-#FFFAF0 FloralWhite
-#228B22 ForestGreen
-#FF00FF Fuchsia
-#DCDCDC Gainsboro
-#F8F8FF GhostWhite
-#FFD700 Gold
-#DAA520 Goldenrod
-#808080 Gray
-#008000 Green
-#ADFF2F GreenYellow
-#F0FFF0 Honeydew
-#FF69B4 HotPink
-#CD5C5C IndianRed
-#4B0082 Indigo
-#FFFFF0 Ivory
-#F0E68C Khaki
-#E6E6FA Lavender
-#FFF0F5 LavenderBlush
-#7CFC00 LawnGreen
-#FFFACD LemonChiffon
-#ADD8E6 LightBlue
-#F08080 LightCoral
-#E0FFFF LightCyan
-#FAFAD2 LightGoldenrodYellow
-#90EE90 LightGreen
-#D3D3D3 LightGrey
-#FFB6C1 LightPink
-#FFA07A LightSalmon
-#20B2AA LightSeaGreen
-#87CEFA LightSkyBlue
-#8470FF LightSlateBlue
-#778899 LightSlateGray
-#B0C4DE LightSteelBlue
-#FFFFE0 LightYellow
-#00FF00 Lime
-#32CD32 LimeGreen
-#FAF0E6 Linen
-#800000 Maroon
-#66CDAA MediumAquamarine
-#0000CD MediumBlue
-#BA55D3 MediumOrchid
-#9370DB MediumPurple
-#3CB371 MediumSeaGreen
-#7B68EE MediumSlateBlue
-#00FA9A MediumSpringGreen
-#48D1CC MediumTurquoise
-#C71585 MediumVioletRed
-#191970 MidnightBlue
-#F5FFFA MintCream
-#FFE4E1 MistyRose
-#FFE4B5 Moccasin
-#FFDEAD NavajoWhite
-#000080 Navy
-#FDF5E6 OldLace
-#808000 Olive
-#6B8E23 OliveDrab
-#FFA500 Orange
-#FF4500 OrangeRed
-#DA70D6 Orchid
-#EEE8AA PaleGoldenrod
-#98FB98 PaleGreen
-#AFEEEE PaleTurquoise
-#DB7093 PaleVioletRed
-#FFEFD5 PapayaWhip
-#FFDAB9 PeachPuff
-#CD853F Peru
-#FFC0CB Pink
-#DDA0DD Plum
-#B0E0E6 PowderBlue
-#800080 Purple
-#FF0000 Red
-#BC8F8F RosyBrown
-#4169E1 RoyalBlue
-#8B4513 SaddleBrown
-#FA8072 Salmon
-#F4A460 SandyBrown
-#2E8B57 SeaGreen
-#FFF5EE Seashell
-#A0522D Sienna
-#C0C0C0 Silver
-#87CEEB SkyBlue
-#6A5ACD SlateBlue
-#708090 SlateGray
-#FFFAFA Snow
-#00FF7F SpringGreen
-#4682B4 SteelBlue
-#D2B48C Tan
-#008080 Teal
-#D8BFD8 Thistle
-#FF6347 Tomato
-#40E0D0 Turquoise
-#EE82EE Violet
-#D02090 VioletRed
-#F5DEB3 Wheat
-#FFFFFF White
-#F5F5F5 WhiteSmoke
-#FFFF00 Yellow
-#9ACD32 YellowGreen
\ No newline at end of file
diff --git a/bin/Debug/DesertPaintLab/template/dp_reactions.txt b/bin/Debug/DesertPaintLab/template/dp_reactions.txt
deleted file mode 100644
--- a/bin/Debug/DesertPaintLab/template/dp_reactions.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-
\ No newline at end of file
diff --git a/bin/Debug/DesertPaintLab/template/ingredients.txt b/bin/Debug/DesertPaintLab/template/ingredients.txt
deleted file mode 100644
--- a/bin/Debug/DesertPaintLab/template/ingredients.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Ingredients are in the form:
-// Name | RGB values | cost | enabled (Y/N) | bulk/normal | max items per paint (1-20)
-//
-// It is recommended to only change the cost value
-// It is not recommended to set many of the ingredients above 10 per paint
-
-Cabbage | 128, 64, 144 | 8 | Y | bulk | 10
-Carrot | 224, 112, 32 | 8 | Y | bulk | 10
-Clay | 128, 96, 32 | 10 | Y | bulk | 20
-DeadTongue | 112, 64, 64 | 500 | Y | normal | 4
-ToadSkin | 48, 96, 48 | 500 | Y | normal | 4
-EarthLight | 128, 240, 224 | 10000 | Y | normal | 4
-RedSand | 144, 16, 24 | 4 | Y | bulk | 20
-Lead | 80, 80, 96 | 50 | Y | normal | 6
-Silver | 16, 16, 32 | 50 | Y | normal | 6
-Iron | 96, 48, 32 | 30 | Y | normal | 8
-Copper | 64, 192, 192 | 30 | Y | normal | 8
-Sulfur | catalyst | 15 | Y | normal | 1
-Potash | catalyst | 50 | Y | normal | 1
-Lime | catalyst | 20 | Y | normal | 1
-Saltpeter | catalyst | 10 | Y | normal | 1
diff --git a/gtk-gui/DesertPaintLab.RecipeGeneratorWindow.cs b/gtk-gui/DesertPaintLab.RecipeGeneratorWindow.cs
--- a/gtk-gui/DesertPaintLab.RecipeGeneratorWindow.cs
+++ b/gtk-gui/DesertPaintLab.RecipeGeneratorWindow.cs
@@ -14,6 +14,8 @@ namespace DesertPaintLab
private global::Gtk.Action IngredientsAction;
+ private global::Gtk.Action CopyToClipboardAction;
+
private global::Gtk.VBox vbox2;
private global::Gtk.MenuBar menubar1;
@@ -22,25 +24,47 @@ namespace DesertPaintLab
private global::Gtk.VBox vbox8;
- private global::Gtk.Label label3;
+ private global::Gtk.HBox hbox2;
private global::Gtk.SpinButton maxIngredientsSpinButton;
+ private global::Gtk.Label label3;
+
private global::Gtk.HSeparator hseparator3;
- private global::Gtk.Label label4;
+ private global::Gtk.HBox hbox4;
private global::Gtk.SpinButton maxRecipeSpinButton;
+ private global::Gtk.Label label4;
+
private global::Gtk.HSeparator hseparator4;
+ private global::Gtk.HBox hbox5;
+
+ private global::Gtk.SpinButton fullQuantityDepthSpinButton;
+
private global::Gtk.Label label8;
- private global::Gtk.SpinButton fullQuantityDepthSpinButton;
+ private global::Gtk.HSeparator hseparator5;
+
+ private global::Gtk.HBox hbox6;
+
+ private global::Gtk.SpinButton fullQuantitySpinButton;
private global::Gtk.Label label9;
- private global::Gtk.SpinButton fullQuantitySpinButton;
+ private global::Gtk.Frame frame3;
+
+ private global::Gtk.Alignment GtkAlignment1;
+
+ private global::Gtk.ScrolledWindow scrolledwindow2;
+
+ private global::Gtk.TreeView reagentListView;
+
+ private global::Gtk.Label GtkLabel4;
+
+ private global::Gtk.HSeparator hseparator6;
private global::Gtk.ScrolledWindow GtkScrolledWindow1;
@@ -50,14 +74,14 @@ namespace DesertPaintLab
private global::Gtk.Frame frame2;
- private global::Gtk.Alignment GtkAlignment;
+ private global::Gtk.ScrolledWindow GtkScrolledWindow;
- private global::Gtk.ScrolledWindow scrolledwindow1;
-
- private global::Gtk.VBox recipeListBox;
+ private global::Gtk.TreeView recipeIngredientsView;
private global::Gtk.Label recipeLabel;
+ private global::Gtk.Button button919;
+
private global::DesertPaintLab.PaintSwatch paintSwatch;
private global::Gtk.HBox hbox3;
@@ -94,6 +118,9 @@ namespace DesertPaintLab
this.IngredientsAction = new global::Gtk.Action ("IngredientsAction", "Ingredients", null, null);
this.IngredientsAction.ShortLabel = "Ingredients";
w1.Add (this.IngredientsAction, null);
+ this.CopyToClipboardAction = new global::Gtk.Action ("CopyToClipboardAction", "Copy to Clipboard", null, null);
+ this.CopyToClipboardAction.ShortLabel = "Copy to Clipboard";
+ w1.Add (this.CopyToClipboardAction, null);
this.UIManager.InsertActionGroup (w1, 0);
this.AddAccelGroup (this.UIManager.AccelGroup);
this.Name = "DesertPaintLab.RecipeGeneratorWindow";
@@ -105,7 +132,7 @@ namespace DesertPaintLab
this.vbox2.Spacing = 6;
this.vbox2.BorderWidth = ((uint)(8));
// Container child vbox2.Gtk.Box+BoxChild
- this.UIManager.AddUiFromString ("");
+ this.UIManager.AddUiFromString ("");
this.menubar1 = ((global::Gtk.MenuBar)(this.UIManager.GetWidget ("/menubar1")));
this.menubar1.Name = "menubar1";
this.vbox2.Add (this.menubar1);
@@ -122,113 +149,196 @@ namespace DesertPaintLab
this.vbox8.Name = "vbox8";
this.vbox8.Spacing = 6;
// Container child vbox8.Gtk.Box+BoxChild
- this.label3 = new global::Gtk.Label ();
- this.label3.Name = "label3";
- this.label3.LabelProp = "Maximum Ingredients";
- this.vbox8.Add (this.label3);
- global::Gtk.Box.BoxChild w3 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.label3]));
- w3.Position = 0;
- w3.Expand = false;
- w3.Fill = false;
- // Container child vbox8.Gtk.Box+BoxChild
+ this.hbox2 = new global::Gtk.HBox ();
+ this.hbox2.Name = "hbox2";
+ this.hbox2.Spacing = 6;
+ // Container child hbox2.Gtk.Box+BoxChild
this.maxIngredientsSpinButton = new global::Gtk.SpinButton (0, 14, 1);
this.maxIngredientsSpinButton.CanFocus = true;
this.maxIngredientsSpinButton.Name = "maxIngredientsSpinButton";
this.maxIngredientsSpinButton.Adjustment.PageIncrement = 10;
this.maxIngredientsSpinButton.ClimbRate = 1;
this.maxIngredientsSpinButton.Numeric = true;
- this.vbox8.Add (this.maxIngredientsSpinButton);
- global::Gtk.Box.BoxChild w4 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.maxIngredientsSpinButton]));
+ this.hbox2.Add (this.maxIngredientsSpinButton);
+ global::Gtk.Box.BoxChild w3 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.maxIngredientsSpinButton]));
+ w3.Position = 0;
+ w3.Expand = false;
+ w3.Fill = false;
+ // Container child hbox2.Gtk.Box+BoxChild
+ this.label3 = new global::Gtk.Label ();
+ this.label3.Name = "label3";
+ this.label3.LabelProp = "Maximum Ingredients";
+ this.hbox2.Add (this.label3);
+ global::Gtk.Box.BoxChild w4 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.label3]));
w4.Position = 1;
w4.Expand = false;
w4.Fill = false;
+ this.vbox8.Add (this.hbox2);
+ global::Gtk.Box.BoxChild w5 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hbox2]));
+ w5.Position = 0;
+ w5.Expand = false;
+ w5.Fill = false;
// Container child vbox8.Gtk.Box+BoxChild
this.hseparator3 = new global::Gtk.HSeparator ();
this.hseparator3.Name = "hseparator3";
this.vbox8.Add (this.hseparator3);
- global::Gtk.Box.BoxChild w5 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hseparator3]));
- w5.Position = 2;
- w5.Expand = false;
- w5.Fill = false;
- // Container child vbox8.Gtk.Box+BoxChild
- this.label4 = new global::Gtk.Label ();
- this.label4.Name = "label4";
- this.label4.LabelProp = "Max Total Quantity";
- this.label4.UseMarkup = true;
- this.label4.Wrap = true;
- this.vbox8.Add (this.label4);
- global::Gtk.Box.BoxChild w6 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.label4]));
- w6.Position = 3;
+ global::Gtk.Box.BoxChild w6 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hseparator3]));
+ w6.Position = 1;
w6.Expand = false;
w6.Fill = false;
- w6.Padding = ((uint)(8));
// Container child vbox8.Gtk.Box+BoxChild
+ this.hbox4 = new global::Gtk.HBox ();
+ this.hbox4.Name = "hbox4";
+ this.hbox4.Spacing = 6;
+ // Container child hbox4.Gtk.Box+BoxChild
this.maxRecipeSpinButton = new global::Gtk.SpinButton (0, 100, 1);
this.maxRecipeSpinButton.CanFocus = true;
this.maxRecipeSpinButton.Name = "maxRecipeSpinButton";
this.maxRecipeSpinButton.Adjustment.PageIncrement = 10;
this.maxRecipeSpinButton.ClimbRate = 1;
this.maxRecipeSpinButton.Numeric = true;
- this.vbox8.Add (this.maxRecipeSpinButton);
- global::Gtk.Box.BoxChild w7 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.maxRecipeSpinButton]));
- w7.Position = 4;
+ this.hbox4.Add (this.maxRecipeSpinButton);
+ global::Gtk.Box.BoxChild w7 = ((global::Gtk.Box.BoxChild)(this.hbox4 [this.maxRecipeSpinButton]));
+ w7.Position = 0;
w7.Expand = false;
w7.Fill = false;
+ // Container child hbox4.Gtk.Box+BoxChild
+ this.label4 = new global::Gtk.Label ();
+ this.label4.Name = "label4";
+ this.label4.LabelProp = "Max Total Quantity";
+ this.label4.UseMarkup = true;
+ this.label4.Wrap = true;
+ this.hbox4.Add (this.label4);
+ global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.hbox4 [this.label4]));
+ w8.Position = 1;
+ w8.Expand = false;
+ w8.Fill = false;
+ this.vbox8.Add (this.hbox4);
+ global::Gtk.Box.BoxChild w9 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hbox4]));
+ w9.Position = 2;
+ w9.Expand = false;
+ w9.Fill = false;
// Container child vbox8.Gtk.Box+BoxChild
this.hseparator4 = new global::Gtk.HSeparator ();
this.hseparator4.Name = "hseparator4";
this.vbox8.Add (this.hseparator4);
- global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hseparator4]));
- w8.Position = 5;
- w8.Expand = false;
- w8.Fill = false;
+ global::Gtk.Box.BoxChild w10 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hseparator4]));
+ w10.Position = 3;
+ w10.Expand = false;
+ w10.Fill = false;
+ w10.Padding = ((uint)(8));
// Container child vbox8.Gtk.Box+BoxChild
- this.label8 = new global::Gtk.Label ();
- this.label8.Name = "label8";
- this.label8.LabelProp = "Full Quantity Depth";
- this.vbox8.Add (this.label8);
- global::Gtk.Box.BoxChild w9 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.label8]));
- w9.Position = 6;
- w9.Expand = false;
- w9.Fill = false;
- // Container child vbox8.Gtk.Box+BoxChild
+ this.hbox5 = new global::Gtk.HBox ();
+ this.hbox5.Name = "hbox5";
+ this.hbox5.Spacing = 6;
+ // Container child hbox5.Gtk.Box+BoxChild
this.fullQuantityDepthSpinButton = new global::Gtk.SpinButton (0, 15, 1);
this.fullQuantityDepthSpinButton.CanFocus = true;
this.fullQuantityDepthSpinButton.Name = "fullQuantityDepthSpinButton";
this.fullQuantityDepthSpinButton.Adjustment.PageIncrement = 10;
this.fullQuantityDepthSpinButton.ClimbRate = 1;
this.fullQuantityDepthSpinButton.Numeric = true;
- this.vbox8.Add (this.fullQuantityDepthSpinButton);
- global::Gtk.Box.BoxChild w10 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.fullQuantityDepthSpinButton]));
- w10.Position = 7;
- w10.Expand = false;
- w10.Fill = false;
- // Container child vbox8.Gtk.Box+BoxChild
- this.label9 = new global::Gtk.Label ();
- this.label9.Name = "label9";
- this.label9.LabelProp = "FullQuantity";
- this.vbox8.Add (this.label9);
- global::Gtk.Box.BoxChild w11 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.label9]));
- w11.Position = 8;
+ this.hbox5.Add (this.fullQuantityDepthSpinButton);
+ global::Gtk.Box.BoxChild w11 = ((global::Gtk.Box.BoxChild)(this.hbox5 [this.fullQuantityDepthSpinButton]));
+ w11.Position = 0;
w11.Expand = false;
w11.Fill = false;
+ // Container child hbox5.Gtk.Box+BoxChild
+ this.label8 = new global::Gtk.Label ();
+ this.label8.Name = "label8";
+ this.label8.LabelProp = "Full Quantity Depth";
+ this.hbox5.Add (this.label8);
+ global::Gtk.Box.BoxChild w12 = ((global::Gtk.Box.BoxChild)(this.hbox5 [this.label8]));
+ w12.Position = 1;
+ w12.Expand = false;
+ w12.Fill = false;
+ this.vbox8.Add (this.hbox5);
+ global::Gtk.Box.BoxChild w13 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hbox5]));
+ w13.Position = 4;
+ w13.Expand = false;
+ w13.Fill = false;
// Container child vbox8.Gtk.Box+BoxChild
+ this.hseparator5 = new global::Gtk.HSeparator ();
+ this.hseparator5.Name = "hseparator5";
+ this.vbox8.Add (this.hseparator5);
+ global::Gtk.Box.BoxChild w14 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hseparator5]));
+ w14.Position = 5;
+ w14.Expand = false;
+ w14.Fill = false;
+ // Container child vbox8.Gtk.Box+BoxChild
+ this.hbox6 = new global::Gtk.HBox ();
+ this.hbox6.Name = "hbox6";
+ this.hbox6.Spacing = 6;
+ // Container child hbox6.Gtk.Box+BoxChild
this.fullQuantitySpinButton = new global::Gtk.SpinButton (0, 30, 1);
this.fullQuantitySpinButton.CanFocus = true;
this.fullQuantitySpinButton.Name = "fullQuantitySpinButton";
this.fullQuantitySpinButton.Adjustment.PageIncrement = 10;
this.fullQuantitySpinButton.ClimbRate = 1;
this.fullQuantitySpinButton.Numeric = true;
- this.vbox8.Add (this.fullQuantitySpinButton);
- global::Gtk.Box.BoxChild w12 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.fullQuantitySpinButton]));
- w12.Position = 9;
- w12.Expand = false;
- w12.Fill = false;
+ this.hbox6.Add (this.fullQuantitySpinButton);
+ global::Gtk.Box.BoxChild w15 = ((global::Gtk.Box.BoxChild)(this.hbox6 [this.fullQuantitySpinButton]));
+ w15.Position = 0;
+ w15.Expand = false;
+ w15.Fill = false;
+ // Container child hbox6.Gtk.Box+BoxChild
+ this.label9 = new global::Gtk.Label ();
+ this.label9.Name = "label9";
+ this.label9.LabelProp = "FullQuantity";
+ this.hbox6.Add (this.label9);
+ global::Gtk.Box.BoxChild w16 = ((global::Gtk.Box.BoxChild)(this.hbox6 [this.label9]));
+ w16.Position = 1;
+ w16.Expand = false;
+ w16.Fill = false;
+ this.vbox8.Add (this.hbox6);
+ global::Gtk.Box.BoxChild w17 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hbox6]));
+ w17.Position = 6;
+ w17.Expand = false;
+ w17.Fill = false;
+ // Container child vbox8.Gtk.Box+BoxChild
+ this.frame3 = new global::Gtk.Frame ();
+ this.frame3.Name = "frame3";
+ this.frame3.ShadowType = ((global::Gtk.ShadowType)(0));
+ // Container child frame3.Gtk.Container+ContainerChild
+ this.GtkAlignment1 = new global::Gtk.Alignment (0F, 0F, 1F, 1F);
+ this.GtkAlignment1.Name = "GtkAlignment1";
+ this.GtkAlignment1.LeftPadding = ((uint)(12));
+ // Container child GtkAlignment1.Gtk.Container+ContainerChild
+ this.scrolledwindow2 = new global::Gtk.ScrolledWindow ();
+ this.scrolledwindow2.CanFocus = true;
+ this.scrolledwindow2.Name = "scrolledwindow2";
+ this.scrolledwindow2.ShadowType = ((global::Gtk.ShadowType)(1));
+ // Container child scrolledwindow2.Gtk.Container+ContainerChild
+ this.reagentListView = new global::Gtk.TreeView ();
+ this.reagentListView.WidthRequest = 300;
+ this.reagentListView.CanFocus = true;
+ this.reagentListView.Name = "reagentListView";
+ this.scrolledwindow2.Add (this.reagentListView);
+ this.GtkAlignment1.Add (this.scrolledwindow2);
+ this.frame3.Add (this.GtkAlignment1);
+ this.GtkLabel4 = new global::Gtk.Label ();
+ this.GtkLabel4.Name = "GtkLabel4";
+ this.GtkLabel4.LabelProp = "Ingredients";
+ this.GtkLabel4.UseMarkup = true;
+ this.frame3.LabelWidget = this.GtkLabel4;
+ this.vbox8.Add (this.frame3);
+ global::Gtk.Box.BoxChild w21 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.frame3]));
+ w21.PackType = ((global::Gtk.PackType)(1));
+ w21.Position = 7;
+ // Container child vbox8.Gtk.Box+BoxChild
+ this.hseparator6 = new global::Gtk.HSeparator ();
+ this.hseparator6.Name = "hseparator6";
+ this.vbox8.Add (this.hseparator6);
+ global::Gtk.Box.BoxChild w22 = ((global::Gtk.Box.BoxChild)(this.vbox8 [this.hseparator6]));
+ w22.PackType = ((global::Gtk.PackType)(1));
+ w22.Position = 8;
+ w22.Expand = false;
+ w22.Fill = false;
this.hbox1.Add (this.vbox8);
- global::Gtk.Box.BoxChild w13 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.vbox8]));
- w13.Position = 0;
- w13.Expand = false;
- w13.Fill = false;
+ global::Gtk.Box.BoxChild w23 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.vbox8]));
+ w23.Position = 0;
+ w23.Expand = false;
+ w23.Fill = false;
// Container child hbox1.Gtk.Box+BoxChild
this.GtkScrolledWindow1 = new global::Gtk.ScrolledWindow ();
this.GtkScrolledWindow1.Name = "GtkScrolledWindow1";
@@ -240,8 +350,8 @@ namespace DesertPaintLab
this.recipeList.Name = "recipeList";
this.GtkScrolledWindow1.Add (this.recipeList);
this.hbox1.Add (this.GtkScrolledWindow1);
- global::Gtk.Box.BoxChild w15 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.GtkScrolledWindow1]));
- w15.Position = 1;
+ global::Gtk.Box.BoxChild w25 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.GtkScrolledWindow1]));
+ w25.Position = 1;
// Container child hbox1.Gtk.Box+BoxChild
this.vbox3 = new global::Gtk.VBox ();
this.vbox3.Name = "vbox3";
@@ -253,51 +363,50 @@ namespace DesertPaintLab
this.frame2.Name = "frame2";
this.frame2.ShadowType = ((global::Gtk.ShadowType)(0));
// Container child frame2.Gtk.Container+ContainerChild
- this.GtkAlignment = new global::Gtk.Alignment (0F, 0F, 1F, 1F);
- this.GtkAlignment.Name = "GtkAlignment";
- this.GtkAlignment.LeftPadding = ((uint)(12));
- // Container child GtkAlignment.Gtk.Container+ContainerChild
- this.scrolledwindow1 = new global::Gtk.ScrolledWindow ();
- this.scrolledwindow1.CanFocus = true;
- this.scrolledwindow1.Name = "scrolledwindow1";
- this.scrolledwindow1.ShadowType = ((global::Gtk.ShadowType)(1));
- // Container child scrolledwindow1.Gtk.Container+ContainerChild
- global::Gtk.Viewport w16 = new global::Gtk.Viewport ();
- w16.ShadowType = ((global::Gtk.ShadowType)(0));
- // Container child GtkViewport.Gtk.Container+ContainerChild
- this.recipeListBox = new global::Gtk.VBox ();
- this.recipeListBox.Name = "recipeListBox";
- this.recipeListBox.Homogeneous = true;
- this.recipeListBox.Spacing = 6;
- this.recipeListBox.BorderWidth = ((uint)(1));
- w16.Add (this.recipeListBox);
- this.scrolledwindow1.Add (w16);
- this.GtkAlignment.Add (this.scrolledwindow1);
- this.frame2.Add (this.GtkAlignment);
+ this.GtkScrolledWindow = new global::Gtk.ScrolledWindow ();
+ this.GtkScrolledWindow.Name = "GtkScrolledWindow";
+ this.GtkScrolledWindow.ShadowType = ((global::Gtk.ShadowType)(1));
+ // Container child GtkScrolledWindow.Gtk.Container+ContainerChild
+ this.recipeIngredientsView = new global::Gtk.TreeView ();
+ this.recipeIngredientsView.CanFocus = true;
+ this.recipeIngredientsView.Name = "recipeIngredientsView";
+ this.GtkScrolledWindow.Add (this.recipeIngredientsView);
+ this.frame2.Add (this.GtkScrolledWindow);
this.recipeLabel = new global::Gtk.Label ();
this.recipeLabel.Name = "recipeLabel";
this.recipeLabel.LabelProp = "Recipe";
this.recipeLabel.UseMarkup = true;
this.frame2.LabelWidget = this.recipeLabel;
this.vbox3.Add (this.frame2);
- global::Gtk.Box.BoxChild w21 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.frame2]));
- w21.Position = 0;
+ global::Gtk.Box.BoxChild w28 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.frame2]));
+ w28.Position = 0;
+ // Container child vbox3.Gtk.Box+BoxChild
+ this.button919 = new global::Gtk.Button ();
+ this.button919.CanFocus = true;
+ this.button919.Name = "button919";
+ this.button919.UseUnderline = true;
+ this.button919.Label = "Copy";
+ this.vbox3.Add (this.button919);
+ global::Gtk.Box.BoxChild w29 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.button919]));
+ w29.Position = 1;
+ w29.Expand = false;
+ w29.Fill = false;
// Container child vbox3.Gtk.Box+BoxChild
this.paintSwatch = new global::DesertPaintLab.PaintSwatch ();
this.paintSwatch.HeightRequest = 200;
this.paintSwatch.Events = ((global::Gdk.EventMask)(256));
this.paintSwatch.Name = "paintSwatch";
this.vbox3.Add (this.paintSwatch);
- global::Gtk.Box.BoxChild w22 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.paintSwatch]));
- w22.Position = 1;
+ global::Gtk.Box.BoxChild w30 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.paintSwatch]));
+ w30.Position = 2;
this.hbox1.Add (this.vbox3);
- global::Gtk.Box.BoxChild w23 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.vbox3]));
- w23.Position = 2;
- w23.Expand = false;
- w23.Fill = false;
+ global::Gtk.Box.BoxChild w31 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.vbox3]));
+ w31.Position = 2;
+ w31.Expand = false;
+ w31.Fill = false;
this.vbox2.Add (this.hbox1);
- global::Gtk.Box.BoxChild w24 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox1]));
- w24.Position = 1;
+ global::Gtk.Box.BoxChild w32 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox1]));
+ w32.Position = 1;
// Container child vbox2.Gtk.Box+BoxChild
this.hbox3 = new global::Gtk.HBox ();
this.hbox3.Name = "hbox3";
@@ -306,8 +415,8 @@ namespace DesertPaintLab
this.hseparator2 = new global::Gtk.HSeparator ();
this.hseparator2.Name = "hseparator2";
this.hbox3.Add (this.hseparator2);
- global::Gtk.Box.BoxChild w25 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.hseparator2]));
- w25.Position = 0;
+ global::Gtk.Box.BoxChild w33 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.hseparator2]));
+ w33.Position = 0;
// Container child hbox3.Gtk.Box+BoxChild
this.stopResumeButton = new global::Gtk.Button ();
this.stopResumeButton.Sensitive = false;
@@ -316,21 +425,21 @@ namespace DesertPaintLab
this.stopResumeButton.UseUnderline = true;
this.stopResumeButton.Label = "Stop";
this.hbox3.Add (this.stopResumeButton);
- global::Gtk.Box.BoxChild w26 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.stopResumeButton]));
- w26.Position = 1;
- w26.Expand = false;
- w26.Fill = false;
- w26.Padding = ((uint)(20));
+ global::Gtk.Box.BoxChild w34 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.stopResumeButton]));
+ w34.Position = 1;
+ w34.Expand = false;
+ w34.Fill = false;
+ w34.Padding = ((uint)(20));
// Container child hbox3.Gtk.Box+BoxChild
this.countLabel = new global::Gtk.Label ();
this.countLabel.Name = "countLabel";
this.countLabel.LabelProp = "0/192";
this.hbox3.Add (this.countLabel);
- global::Gtk.Box.BoxChild w27 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.countLabel]));
- w27.Position = 2;
- w27.Expand = false;
- w27.Fill = false;
- w27.Padding = ((uint)(40));
+ global::Gtk.Box.BoxChild w35 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.countLabel]));
+ w35.Position = 2;
+ w35.Expand = false;
+ w35.Fill = false;
+ w35.Padding = ((uint)(40));
// Container child hbox3.Gtk.Box+BoxChild
this.beginButton = new global::Gtk.Button ();
this.beginButton.CanFocus = true;
@@ -338,53 +447,55 @@ namespace DesertPaintLab
this.beginButton.UseUnderline = true;
this.beginButton.Label = "Begin";
this.hbox3.Add (this.beginButton);
- global::Gtk.Box.BoxChild w28 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.beginButton]));
- w28.Position = 3;
- w28.Expand = false;
- w28.Fill = false;
- w28.Padding = ((uint)(20));
+ global::Gtk.Box.BoxChild w36 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.beginButton]));
+ w36.Position = 3;
+ w36.Expand = false;
+ w36.Fill = false;
+ w36.Padding = ((uint)(20));
// Container child hbox3.Gtk.Box+BoxChild
this.hseparator1 = new global::Gtk.HSeparator ();
this.hseparator1.Name = "hseparator1";
this.hbox3.Add (this.hseparator1);
- global::Gtk.Box.BoxChild w29 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.hseparator1]));
- w29.Position = 4;
+ global::Gtk.Box.BoxChild w37 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.hseparator1]));
+ w37.Position = 4;
this.vbox2.Add (this.hbox3);
- global::Gtk.Box.BoxChild w30 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox3]));
- w30.Position = 2;
- w30.Expand = false;
- w30.Fill = false;
+ global::Gtk.Box.BoxChild w38 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox3]));
+ w38.Position = 2;
+ w38.Expand = false;
+ w38.Fill = false;
// Container child vbox2.Gtk.Box+BoxChild
this.statusLabel = new global::Gtk.Label ();
this.statusLabel.Name = "statusLabel";
this.vbox2.Add (this.statusLabel);
- global::Gtk.Box.BoxChild w31 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.statusLabel]));
- w31.PackType = ((global::Gtk.PackType)(1));
- w31.Position = 3;
- w31.Expand = false;
- w31.Fill = false;
+ global::Gtk.Box.BoxChild w39 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.statusLabel]));
+ w39.PackType = ((global::Gtk.PackType)(1));
+ w39.Position = 3;
+ w39.Expand = false;
+ w39.Fill = false;
// Container child vbox2.Gtk.Box+BoxChild
this.progressBar = new global::Gtk.ProgressBar ();
this.progressBar.Name = "progressBar";
this.vbox2.Add (this.progressBar);
- global::Gtk.Box.BoxChild w32 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.progressBar]));
- w32.PackType = ((global::Gtk.PackType)(1));
- w32.Position = 4;
- w32.Expand = false;
- w32.Fill = false;
+ global::Gtk.Box.BoxChild w40 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.progressBar]));
+ w40.PackType = ((global::Gtk.PackType)(1));
+ w40.Position = 4;
+ w40.Expand = false;
+ w40.Fill = false;
this.Add (this.vbox2);
if ((this.Child != null)) {
this.Child.ShowAll ();
}
this.DefaultWidth = 887;
- this.DefaultHeight = 570;
+ this.DefaultHeight = 577;
this.Show ();
this.ExportToWikiAction.Activated += new global::System.EventHandler (this.OnExportToWiki);
this.IngredientsAction.Activated += new global::System.EventHandler (this.OnShowIngredients);
+ this.CopyToClipboardAction.Activated += new global::System.EventHandler (this.OnCopyRecipeListToClipboard);
this.maxIngredientsSpinButton.ValueChanged += new global::System.EventHandler (this.OnMaxIngredientsChanged);
this.maxRecipeSpinButton.ValueChanged += new global::System.EventHandler (this.OnMaxRecipeChanged);
this.fullQuantityDepthSpinButton.ValueChanged += new global::System.EventHandler (this.OnFullQuantityDepthChanged);
- this.fullQuantitySpinButton.Input += new global::Gtk.InputHandler (this.OnFullQuantityChanged);
+ this.fullQuantitySpinButton.ValueChanged += new global::System.EventHandler (this.OnFullQuantityChanged);
+ this.button919.Clicked += new global::System.EventHandler (this.OnCopyRecipeToClipboard);
this.stopResumeButton.Clicked += new global::System.EventHandler (this.OnStopResume);
this.beginButton.Clicked += new global::System.EventHandler (this.OnBegin);
}
diff --git a/gtk-gui/gui.stetic b/gtk-gui/gui.stetic
--- a/gtk-gui/gui.stetic
+++ b/gtk-gui/gui.stetic
@@ -1154,7 +1154,7 @@ You can either import an existing Practi
-
+
Action
@@ -1178,6 +1178,12 @@ You can either import an existing Practi
Ingredients
+
+ Action
+ Copy to Clipboard
+ Copy to Clipboard
+
+
Recipe Generator
@@ -1193,9 +1199,7 @@ You can either import an existing Practi
-
-
-
+
@@ -1215,9 +1219,39 @@ You can either import an existing Practi
6
-
+
- Maximum Ingredients
+ 6
+
+
+
+ True
+ 14
+ 10
+ 1
+ 1
+ True
+
+
+
+ 0
+ True
+ False
+ False
+
+
+
+
+
+ Maximum Ingredients
+
+
+ 1
+ True
+ False
+ False
+
+
0
@@ -1227,28 +1261,54 @@ You can either import an existing Practi
-
-
- True
- 14
- 10
- 1
- 1
- True
-
-
-
- 1
- True
- False
- False
-
-
-
+ 1
+ True
+ False
+ False
+
+
+
+
+
+ 6
+
+
+
+ True
+ 100
+ 10
+ 1
+ 1
+ True
+
+
+
+ 0
+ True
+ False
+ False
+
+
+
+
+
+ Max Total Quantity
+ True
+ True
+
+
+ 1
+ True
+ False
+ False
+
+
+
+
2
True
False
@@ -1256,11 +1316,8 @@ You can either import an existing Practi
-
+
- Max Total Quantity
- True
- True
3
@@ -1271,15 +1328,39 @@ You can either import an existing Practi
-
+
- True
- 100
- 10
- 1
- 1
- True
-
+ 6
+
+
+
+ True
+ 15
+ 10
+ 1
+ 1
+ True
+
+
+
+ 0
+ True
+ False
+ False
+
+
+
+
+
+ Full Quantity Depth
+
+
+ 1
+ True
+ False
+ False
+
+
4
@@ -1289,7 +1370,7 @@ You can either import an existing Practi
-
+
@@ -1300,9 +1381,39 @@ You can either import an existing Practi
-
+
- Full Quantity Depth
+ 6
+
+
+
+ True
+ 30
+ 10
+ 1
+ 1
+ True
+
+
+
+ 0
+ True
+ False
+ False
+
+
+
+
+
+ FullQuantity
+
+
+ 1
+ True
+ False
+ False
+
+
6
@@ -1312,53 +1423,60 @@ You can either import an existing Practi
-
+
- True
- 15
- 10
- 1
- 1
- True
-
+ None
+
+
+
+ 0
+ 0
+ 12
+
+
+
+ True
+ In
+
+
+
+ 300
+ True
+
+
+
+
+
+
+
+
+
+ <b>Ingredients</b>
+ True
+
+
+ label_item
+
+
+ End
7
True
- False
- False
-
+
- FullQuantity
+ End
8
True
False
False
-
-
-
- True
- 30
- 10
- 1
- 1
- True
-
-
-
- 9
- True
- False
- False
-
-
0
@@ -1396,39 +1514,14 @@ You can either import an existing Practi
200
None
-
+
- 0
- 0
- 12
+ In
-
+
True
- In
-
-
-
- None
-
-
-
- True
- 6
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
+ True
@@ -1450,13 +1543,29 @@ You can either import an existing Practi
+
+
+ True
+ TextOnly
+ Copy
+ True
+
+
+
+ 1
+ True
+ False
+ False
+
+
+
200
ButtonPressMask
- 1
+ 2
True