Changeset - 63ed2e1d582c
[Not reviewed]
default
3 7 1
Jason Maltzen (jmaltzen) - 9 years ago 2015-12-27 09:37:12
jason.maltzen@unsanctioned.net
Switch recipe generation to breadth-first searching. Move ingredients editing to recipe generator. Add functions to copy single recipe and all recipes to clipboard.
11 files changed with 1340 insertions and 813 deletions:
0 comments (0 inline, 0 general)
DesertPaintLab.csproj
Show inline comments
...
 
@@ -86,2 +86,3 @@
 
    <Compile Include="gtk-gui\DesertPaintLab.ReagentWindow.cs" />
 
    <Compile Include="RecipeSearchNode.cs" />
 
  </ItemGroup>
PaintRecipe.cs
Show inline comments
...
 
@@ -103,2 +103,13 @@ namespace DesertPaintLab
 

	
 
        override public string ToString()
 
        {
 
            string result = Palette.FindNearest(ReactedColor);
 
            result += " |";
 
            foreach (RecipeIngredient ingr in recipe)
 
            {
 
                result += " " + ingr.ToString();
 
            }
 
            return result;
 
        }
 

	
 
        public List<RecipeIngredient> Ingredients
PlayerProfile.cs
Show inline comments
...
 
@@ -408,4 +408,10 @@ namespace DesertPaintLab
 
        {
 
            StreamWriter writer = new StreamWriter(file);
 
            ExportWikiFormat(writer);
 
        }
 
		
 
        public void ExportWikiFormat(TextWriter writer)
 
        {
 
            PaintRecipe recipe;
 
            using (StreamWriter writer = new StreamWriter(file))
 
            using (writer)
 
            {
RecipeGenerator.cs
Show inline comments
...
 
@@ -59,400 +59,13 @@ namespace DesertPaintLab
 
    {
 
        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<Reagent> 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<Reagent> costSortedReagents, uint[] reagents)
 
            {
 
                this.costSortedReagents = new List<Reagent>(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<Reagent> costSortedReagents, uint startReagent)
 
            {
 
                this.costSortedReagents = new List<Reagent>(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<Reagent> 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<Reagent> 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(@"(?<id>\d+),(?<inUse>\d+),(?<weight>\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
 

	
...
 
@@ -470,5 +83,5 @@ namespace DesertPaintLab
 

	
 
        ConcurrentQueue<SearchNode> searchQueue = new ConcurrentQueue<SearchNode>();
 
        ConcurrentQueue<RecipeSearchNode> searchQueue = new ConcurrentQueue<RecipeSearchNode>();
 

	
 
        int recipeCount = 0;
 
        ulong recipeCount = 0;
 

	
...
 
@@ -479,2 +92,4 @@ namespace DesertPaintLab
 

	
 
        StreamWriter log;
 

	
 
        // events
...
 
@@ -486,2 +101,3 @@ namespace DesertPaintLab
 
        {
 
            Mode = SearchType.BREADTH_FIRST;
 
            this.reactions = reactions;
...
 
@@ -502,3 +118,3 @@ namespace DesertPaintLab
 

	
 
        public int RecipeCount
 
        public ulong RecipeCount
 
        {
...
 
@@ -518,2 +134,17 @@ namespace DesertPaintLab
 

	
 
        public string Log
 
        {
 
            set
 
            {
 
                if (value != null)
 
                {
 
                    log = new StreamWriter(value);
 
                }
 
                else
 
                {
 
                    log = null;
 
                }
 
            }
 
        }
 

	
 
        private class ReagentCostSort : IComparer<Reagent>
...
 
@@ -558,6 +189,6 @@ namespace DesertPaintLab
 

	
 
            //this.maxQuantity = maxQuantity;
 
            this.maxReagents = maxReagents;
 
            this.fullQuantity = fullQuantity;
 
            this.fullQuantityDepth = fullQuantityDepth;
 
            this.MaxQuantity = maxQuantity;
 
            this.MaxReagents = maxReagents;
 
            this.FullQuantity = fullQuantity;
 
            this.FullQuantityDepth = fullQuantityDepth;
 

	
...
 
@@ -565,3 +196,2 @@ namespace DesertPaintLab
 
            InitSortedReagents();
 
            this.maxReagents = (uint)Math.Min(costSortedReagents.Count, this.maxReagents);
 

	
...
 
@@ -572,2 +202,3 @@ namespace DesertPaintLab
 
            // 2) any previously-generated recipes
 
            int enabledReagentCount = 0;
 
            PaintRecipe recipe = new PaintRecipe();
...
 
@@ -576,3 +207,5 @@ namespace DesertPaintLab
 
            {
 
                if (!reagent.IsCatalyst && reagent.RecipeMax >= 10 && reagent.Enabled)
 
                if (reagent.Enabled)
 
                {
 
                    if (!reagent.IsCatalyst && ((reagent.RecipeMax >= 10) || ((FullQuantityDepth > 0) && (FullQuantity >= 10))))
 
                {
...
 
@@ -582,3 +215,6 @@ namespace DesertPaintLab
 
                }
 
                    ++enabledReagentCount;
 
            }
 
            }
 
            this.MaxReagents = (uint)Math.Min(enabledReagentCount, this.MaxReagents);
 

	
...
 
@@ -586,3 +222,3 @@ namespace DesertPaintLab
 
            {
 
                SearchNode node;
 
                RecipeSearchNode node;
 
                searchQueue.TryDequeue(out node);
...
 
@@ -593,3 +229,5 @@ namespace DesertPaintLab
 
                {
 
                    SearchNode initialNode = new SearchNode(costSortedReagents, reagentIdx);
 
                    RecipeSearchNode initialNode = new RecipeSearchNode(costSortedReagents, reagentIdx);
 
                    initialNode.FullQuantity = FullQuantity;
 
                    initialNode.FullQuantityDepth = FullQuantityDepth;
 
                    initialNode.MaxQuantity = maxQuantity;
...
 
@@ -600,4 +238,10 @@ namespace DesertPaintLab
 
            
 
            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();
...
 
@@ -615,6 +259,9 @@ namespace DesertPaintLab
 

	
 
            //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)
...
 
@@ -648,7 +295,8 @@ namespace DesertPaintLab
 
            {
 
                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<string, PaintRecipe> pair in recipes)
...
 
@@ -665,3 +313,3 @@ namespace DesertPaintLab
 
                writer.WriteLine("SearchNodes: {0}", searchQueue.Count);
 
                foreach (SearchNode node in searchQueue)
 
                foreach (RecipeSearchNode node in searchQueue)
 
                {
...
 
@@ -700,9 +348,9 @@ namespace DesertPaintLab
 
                            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;
...
 
@@ -712,3 +360,8 @@ namespace DesertPaintLab
 
                            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;
...
 
@@ -747,3 +400,7 @@ namespace DesertPaintLab
 
                                {
 
                                    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);
...
 
@@ -755,2 +412,5 @@ namespace DesertPaintLab
 
                                break;
 
                            case "SearchType":
 
                                Mode = (SearchType)Enum.Parse(typeof(SearchType), match.Groups["value"].Value);
 
                                break;
 
                            default:
...
 
@@ -772,3 +432,3 @@ namespace DesertPaintLab
 
        {
 
            SearchNode node;
 
            RecipeSearchNode node;
 

	
...
 
@@ -788,3 +448,5 @@ namespace DesertPaintLab
 
                {
 
                    uint targetQuantity = node.MaxQuantity + 1;
 
                    if (Mode == SearchType.DEPTH_FIRST)
 
                    {
 
                        uint targetQuantity = (node.ReagentCount <= FullQuantityDepth) ? ((uint)node.ReagentCount * FullQuantity) : node.MaxQuantity + 1;
 
                    do {
...
 
@@ -794,3 +456,3 @@ namespace DesertPaintLab
 

	
 
                    while ((ok = Iterate(node)) && !requestCancel)
 
                        while ((ok = IterateDepthFirst(node)) && !requestCancel)
 
                    {
...
 
@@ -801,2 +463,21 @@ namespace DesertPaintLab
 
                    }
 
                    }
 
                    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)
...
 
@@ -884,4 +565,6 @@ namespace DesertPaintLab
 

	
 
        private bool Iterate(SearchNode node)
 
        private bool IterateDepthFirst(RecipeSearchNode node)
 
        {
 
            TestCurrentRecipe(node);
 

	
 
            // pick recipe quantities at current recipe ingredients/size
...
 
@@ -899,3 +582,3 @@ namespace DesertPaintLab
 
            {
 
                //System.Console.WriteLine("Found next recipee size {0}", node.CurrentTargetQuantity);
 
                //System.Console.WriteLine("Found next recipe size {0}", node.CurrentTargetQuantity);
 
                return true;
...
 
@@ -952,5 +635,142 @@ namespace DesertPaintLab
 

	
 
        private bool NextRecipe(SearchNode node)
 
        private bool IterateBreadthFirst(RecipeSearchNode node)
 
        {
 
            // 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)
 
        {
 
            // First, run the current recipe
 
                                        // 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)
...
 
@@ -966,3 +786,7 @@ namespace DesertPaintLab
 
            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
...
 
@@ -972,2 +796,3 @@ namespace DesertPaintLab
 
                // not possible to make a valid recipe
 
                Console.WriteLine("Insufficient remaining weight");
 
                return false;
...
 
@@ -993,3 +818,3 @@ namespace DesertPaintLab
 
                        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)
...
 
@@ -1006,3 +831,3 @@ namespace DesertPaintLab
 
                    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;
...
 
@@ -1029,3 +854,3 @@ namespace DesertPaintLab
 

	
 
        private bool NextRecipeSize(SearchNode node)
 
        private bool NextRecipeSize(RecipeSearchNode node)
 
        {
RecipeGeneratorWindow.cs
Show inline comments
...
 
@@ -23,2 +23,3 @@
 
using System;
 
using System.IO;
 
using System.Collections.Generic;
...
 
@@ -63,2 +64,5 @@ namespace DesertPaintLab
 

	
 
        Gtk.ListStore reagentListStore;
 
        // end reagent view
 

	
 
        public RecipeGeneratorWindow(PlayerProfile profile) : base(Gtk.WindowType.Toplevel)
...
 
@@ -75,2 +79,3 @@ namespace DesertPaintLab
 

	
 

	
 
            Gtk.TreeViewColumn recipeColorColumn = new Gtk.TreeViewColumn();
...
 
@@ -90,2 +95,6 @@ namespace DesertPaintLab
 

	
 
            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();
...
 
@@ -122,4 +131,10 @@ namespace DesertPaintLab
 
                    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);
...
 
@@ -131,2 +146,61 @@ namespace DesertPaintLab
 
            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();
 
        }
...
 
@@ -167,2 +241,3 @@ namespace DesertPaintLab
 
            fullQuantityDepthSpinButton.Sensitive = false;
 
            reagentListView.Sensitive = false;
 

	
...
 
@@ -214,2 +289,11 @@ namespace DesertPaintLab
 
                    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;
...
 
@@ -249,2 +333,3 @@ namespace DesertPaintLab
 
                fullQuantityDepthSpinButton.Sensitive = true;
 
                reagentListView.Sensitive = false;
 
                //generator = null; // don't. Hang on to generator for resume.
...
 
@@ -368,6 +453,4 @@ namespace DesertPaintLab
 
                {
 
                    foreach (Gtk.Widget child in recipeListBox.AllChildren)
 
                    {
 
                        recipeListBox.Remove(child);
 
                    }
 
                    Gtk.ListStore store = (Gtk.ListStore)recipeIngredientsView.Model;
 
                    store.Clear();
 
                    if (recipe.CheckMissingReactions(ref missingReactions))
...
 
@@ -378,5 +461,3 @@ namespace DesertPaintLab
 
                    {
 
                        Gtk.Label label = new Gtk.Label(ingredient.quantity.ToString() + " " + ingredient.name);
 
                        recipeListBox.PackStart(label);
 
                        label.Show();
 
                        store.AppendValues(ingredient.quantity.ToString(), ingredient.name);
 
                    }
...
 
@@ -423,2 +504,36 @@ namespace DesertPaintLab
 
        }
 

	
 
        // 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();
 
                }
 
    }
...
 
@@ -426,1 +541,68 @@ namespace DesertPaintLab
 

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

	
RecipeSearchNode.cs
Show inline comments
 
new file 100644
 
/*
 
 * 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<Reagent> 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<Reagent> costSortedReagents, uint[] reagents)
 
        {
 
            this.costSortedReagents = new List<Reagent>(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<Reagent> costSortedReagents, uint startReagent)
 
        {
 
            this.costSortedReagents = new List<Reagent>(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<Reagent> 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<Reagent> 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(@"(?<id>\d+),(?<inUse>\d+),(?<weight>\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;
 
        }
 
    }
 
}
 

	
bin/Debug/DesertPaintLab/colors.txt
Show inline comments
 
deleted file
bin/Debug/DesertPaintLab/template/dp_reactions.txt
Show inline comments
 
deleted file
bin/Debug/DesertPaintLab/template/ingredients.txt
Show inline comments
 
deleted file
gtk-gui/DesertPaintLab.RecipeGeneratorWindow.cs
Show inline comments
...
 
@@ -16,2 +16,4 @@ namespace DesertPaintLab
 
		
 
		private global::Gtk.Action CopyToClipboardAction;
 
		
 
		private global::Gtk.VBox vbox2;
...
 
@@ -24,3 +26,3 @@ namespace DesertPaintLab
 
		
 
		private global::Gtk.Label label3;
 
		private global::Gtk.HBox hbox2;
 
		
...
 
@@ -28,5 +30,7 @@ namespace DesertPaintLab
 
		
 
		private global::Gtk.Label label3;
 
		
 
		private global::Gtk.HSeparator hseparator3;
 
		
 
		private global::Gtk.Label label4;
 
		private global::Gtk.HBox hbox4;
 
		
...
 
@@ -34,7 +38,17 @@ namespace DesertPaintLab
 
		
 
		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;
 
		
...
 
@@ -42,3 +56,13 @@ namespace DesertPaintLab
 
		
 
		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;
 
		
...
 
@@ -52,7 +76,5 @@ namespace DesertPaintLab
 
		
 
		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;
 
		
...
 
@@ -60,2 +82,4 @@ namespace DesertPaintLab
 
		
 
		private global::Gtk.Button button919;
 
		
 
		private global::DesertPaintLab.PaintSwatch paintSwatch;
...
 
@@ -96,2 +120,5 @@ namespace DesertPaintLab
 
			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);
...
 
@@ -107,3 +134,3 @@ namespace DesertPaintLab
 
			// Container child vbox2.Gtk.Box+BoxChild
 
			this.UIManager.AddUiFromString ("<ui><menubar name='menubar1'><menu name='ExportAction' action='ExportAction'><menuitem name='ExportToWikiAction' action='ExportToWikiAction'/></menu><menu name='SettingsAction' action='SettingsAction'><menuitem name='IngredientsAction' action='IngredientsAction'/></menu></menubar></ui>");
 
			this.UIManager.AddUiFromString ("<ui><menubar name='menubar1'><menu name='ExportAction' action='ExportAction'><menuitem name='ExportToWikiAction' action='ExportToWikiAction'/><menuitem name='CopyToClipboardAction' action='CopyToClipboardAction'/></menu></menubar></ui>");
 
			this.menubar1 = ((global::Gtk.MenuBar)(this.UIManager.GetWidget ("/menubar1")));
...
 
@@ -124,11 +151,6 @@ namespace DesertPaintLab
 
			// 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);
...
 
@@ -139,4 +161,13 @@ namespace DesertPaintLab
 
			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;
...
 
@@ -144,2 +175,7 @@ namespace DesertPaintLab
 
			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
...
 
@@ -148,19 +184,11 @@ namespace DesertPaintLab
 
			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);
...
 
@@ -171,7 +199,23 @@ namespace DesertPaintLab
 
			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
...
 
@@ -180,16 +224,12 @@ namespace DesertPaintLab
 
			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);
...
 
@@ -200,17 +240,34 @@ namespace DesertPaintLab
 
			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);
...
 
@@ -221,12 +278,65 @@ namespace DesertPaintLab
 
			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 = "<b>Ingredients</b>";
 
			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
...
 
@@ -242,4 +352,4 @@ namespace DesertPaintLab
 
			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
...
 
@@ -255,23 +365,11 @@ namespace DesertPaintLab
 
			// 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 ();
...
 
@@ -282,4 +380,15 @@ namespace DesertPaintLab
 
			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
...
 
@@ -290,12 +399,12 @@ namespace DesertPaintLab
 
			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
...
 
@@ -308,4 +417,4 @@ namespace DesertPaintLab
 
			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
...
 
@@ -318,7 +427,7 @@ namespace DesertPaintLab
 
			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
...
 
@@ -328,7 +437,7 @@ namespace DesertPaintLab
 
			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
...
 
@@ -340,7 +449,7 @@ namespace DesertPaintLab
 
			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
...
 
@@ -349,9 +458,9 @@ namespace DesertPaintLab
 
			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
...
 
@@ -360,7 +469,7 @@ namespace DesertPaintLab
 
			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
...
 
@@ -369,7 +478,7 @@ namespace DesertPaintLab
 
			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);
...
 
@@ -379,3 +488,3 @@ namespace DesertPaintLab
 
			this.DefaultWidth = 887;
 
			this.DefaultHeight = 570;
 
			this.DefaultHeight = 577;
 
			this.Show ();
...
 
@@ -383,2 +492,3 @@ namespace DesertPaintLab
 
			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);
...
 
@@ -386,3 +496,4 @@ namespace DesertPaintLab
 
			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);
gtk-gui/gui.stetic
Show inline comments
...
 
@@ -1156,3 +1156,3 @@ You can either import an existing Practi
 
  </widget>
 
  <widget class="Gtk.Window" id="DesertPaintLab.RecipeGeneratorWindow" design-size="887 570">
 
  <widget class="Gtk.Window" id="DesertPaintLab.RecipeGeneratorWindow" design-size="887 577">
 
    <action-group name="Default">
...
 
@@ -1180,2 +1180,8 @@ You can either import an existing Practi
 
      </action>
 
      <action id="CopyToClipboardAction">
 
        <property name="Type">Action</property>
 
        <property name="Label" translatable="yes">Copy to Clipboard</property>
 
        <property name="ShortLabel" translatable="yes">Copy to Clipboard</property>
 
        <signal name="Activated" handler="OnCopyRecipeListToClipboard" />
 
      </action>
 
    </action-group>
...
 
@@ -1195,5 +1201,3 @@ You can either import an existing Practi
 
                <node type="Menuitem" action="ExportToWikiAction" />
 
              </node>
 
              <node type="Menu" action="SettingsAction">
 
                <node type="Menuitem" action="IngredientsAction" />
 
                <node type="Menuitem" action="CopyToClipboardAction" />
 
              </node>
...
 
@@ -1217,5 +1221,15 @@ You can either import an existing Practi
 
                <child>
 
                  <widget class="Gtk.Label" id="label3">
 
                  <widget class="Gtk.HBox" id="hbox2">
 
                    <property name="MemberName" />
 
                    <property name="Spacing">6</property>
 
                    <child>
 
                      <widget class="Gtk.SpinButton" id="maxIngredientsSpinButton">
 
                    <property name="MemberName" />
 
                    <property name="LabelProp" translatable="yes">Maximum Ingredients</property>
 
                        <property name="CanFocus">True</property>
 
                        <property name="Upper">14</property>
 
                        <property name="PageIncrement">10</property>
 
                        <property name="StepIncrement">1</property>
 
                        <property name="ClimbRate">1</property>
 
                        <property name="Numeric">True</property>
 
                        <signal name="ValueChanged" handler="OnMaxIngredientsChanged" after="yes" />
 
                  </widget>
...
 
@@ -1229,11 +1243,5 @@ You can either import an existing Practi
 
                <child>
 
                  <widget class="Gtk.SpinButton" id="maxIngredientsSpinButton">
 
                      <widget class="Gtk.Label" id="label3">
 
                    <property name="MemberName" />
 
                    <property name="CanFocus">True</property>
 
                    <property name="Upper">14</property>
 
                    <property name="PageIncrement">10</property>
 
                    <property name="StepIncrement">1</property>
 
                    <property name="ClimbRate">1</property>
 
                    <property name="Numeric">True</property>
 
                    <signal name="ValueChanged" handler="OnMaxIngredientsChanged" />
 
                        <property name="LabelProp" translatable="yes">Maximum Ingredients</property>
 
                  </widget>
...
 
@@ -1246,2 +1254,10 @@ You can either import an existing Practi
 
                </child>
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">0</property>
 
                    <property name="AutoSize">True</property>
 
                    <property name="Expand">False</property>
 
                    <property name="Fill">False</property>
 
                  </packing>
 
                </child>
 
                <child>
...
 
@@ -1251,3 +1267,25 @@ You can either import an existing Practi
 
                  <packing>
 
                    <property name="Position">2</property>
 
                    <property name="Position">1</property>
 
                    <property name="AutoSize">True</property>
 
                    <property name="Expand">False</property>
 
                    <property name="Fill">False</property>
 
                  </packing>
 
                </child>
 
                <child>
 
                  <widget class="Gtk.HBox" id="hbox4">
 
                    <property name="MemberName" />
 
                    <property name="Spacing">6</property>
 
                    <child>
 
                      <widget class="Gtk.SpinButton" id="maxRecipeSpinButton">
 
                        <property name="MemberName" />
 
                        <property name="CanFocus">True</property>
 
                        <property name="Upper">100</property>
 
                        <property name="PageIncrement">10</property>
 
                        <property name="StepIncrement">1</property>
 
                        <property name="ClimbRate">1</property>
 
                        <property name="Numeric">True</property>
 
                        <signal name="ValueChanged" handler="OnMaxRecipeChanged" after="yes" />
 
                      </widget>
 
                      <packing>
 
                        <property name="Position">0</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1265,3 +1303,3 @@ You can either import an existing Practi
 
                  <packing>
 
                    <property name="Position">3</property>
 
                        <property name="Position">1</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1269,18 +1307,7 @@ You can either import an existing Practi
 
                    <property name="Fill">False</property>
 
                    <property name="Padding">8</property>
 
                  </packing>
 
                </child>
 
                <child>
 
                  <widget class="Gtk.SpinButton" id="maxRecipeSpinButton">
 
                    <property name="MemberName" />
 
                    <property name="CanFocus">True</property>
 
                    <property name="Upper">100</property>
 
                    <property name="PageIncrement">10</property>
 
                    <property name="StepIncrement">1</property>
 
                    <property name="ClimbRate">1</property>
 
                    <property name="Numeric">True</property>
 
                    <signal name="ValueChanged" handler="OnMaxRecipeChanged" />
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">4</property>
 
                    <property name="Position">2</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1295,3 +1322,26 @@ You can either import an existing Practi
 
                  <packing>
 
                    <property name="Position">5</property>
 
                    <property name="Position">3</property>
 
                    <property name="AutoSize">True</property>
 
                    <property name="Expand">False</property>
 
                    <property name="Fill">False</property>
 
                    <property name="Padding">8</property>
 
                  </packing>
 
                </child>
 
                <child>
 
                  <widget class="Gtk.HBox" id="hbox5">
 
                    <property name="MemberName" />
 
                    <property name="Spacing">6</property>
 
                    <child>
 
                      <widget class="Gtk.SpinButton" id="fullQuantityDepthSpinButton">
 
                        <property name="MemberName" />
 
                        <property name="CanFocus">True</property>
 
                        <property name="Upper">15</property>
 
                        <property name="PageIncrement">10</property>
 
                        <property name="StepIncrement">1</property>
 
                        <property name="ClimbRate">1</property>
 
                        <property name="Numeric">True</property>
 
                        <signal name="ValueChanged" handler="OnFullQuantityDepthChanged" after="yes" />
 
                      </widget>
 
                      <packing>
 
                        <property name="Position">0</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1307,3 +1357,11 @@ You can either import an existing Practi
 
                  <packing>
 
                    <property name="Position">6</property>
 
                        <property name="Position">1</property>
 
                        <property name="AutoSize">True</property>
 
                        <property name="Expand">False</property>
 
                        <property name="Fill">False</property>
 
                      </packing>
 
                    </child>
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">4</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1314,6 +1372,21 @@ You can either import an existing Practi
 
                <child>
 
                  <widget class="Gtk.SpinButton" id="fullQuantityDepthSpinButton">
 
                  <widget class="Gtk.HSeparator" id="hseparator5">
 
                    <property name="MemberName" />
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">5</property>
 
                    <property name="AutoSize">True</property>
 
                    <property name="Expand">False</property>
 
                    <property name="Fill">False</property>
 
                  </packing>
 
                </child>
 
                <child>
 
                  <widget class="Gtk.HBox" id="hbox6">
 
                    <property name="MemberName" />
 
                    <property name="Spacing">6</property>
 
                    <child>
 
                      <widget class="Gtk.SpinButton" id="fullQuantitySpinButton">
 
                    <property name="MemberName" />
 
                    <property name="CanFocus">True</property>
 
                    <property name="Upper">15</property>
 
                        <property name="Upper">30</property>
 
                    <property name="PageIncrement">10</property>
...
 
@@ -1322,6 +1395,6 @@ You can either import an existing Practi
 
                    <property name="Numeric">True</property>
 
                    <signal name="ValueChanged" handler="OnFullQuantityDepthChanged" />
 
                        <signal name="ValueChanged" handler="OnFullQuantityChanged" />
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">7</property>
 
                        <property name="Position">0</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1337,3 +1410,11 @@ You can either import an existing Practi
 
                  <packing>
 
                    <property name="Position">8</property>
 
                        <property name="Position">1</property>
 
                        <property name="AutoSize">True</property>
 
                        <property name="Expand">False</property>
 
                        <property name="Fill">False</property>
 
                      </packing>
 
                    </child>
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">6</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1344,14 +1425,51 @@ You can either import an existing Practi
 
                <child>
 
                  <widget class="Gtk.SpinButton" id="fullQuantitySpinButton">
 
                  <widget class="Gtk.Frame" id="frame3">
 
                    <property name="MemberName" />
 
                    <property name="ShadowType">None</property>
 
                    <child>
 
                      <widget class="Gtk.Alignment" id="GtkAlignment1">
 
                        <property name="MemberName" />
 
                        <property name="Xalign">0</property>
 
                        <property name="Yalign">0</property>
 
                        <property name="LeftPadding">12</property>
 
                        <child>
 
                          <widget class="Gtk.ScrolledWindow" id="scrolledwindow2">
 
                    <property name="MemberName" />
 
                    <property name="CanFocus">True</property>
 
                    <property name="Upper">30</property>
 
                    <property name="PageIncrement">10</property>
 
                    <property name="StepIncrement">1</property>
 
                    <property name="ClimbRate">1</property>
 
                    <property name="Numeric">True</property>
 
                    <signal name="Input" handler="OnFullQuantityChanged" />
 
                            <property name="ShadowType">In</property>
 
                            <child>
 
                              <widget class="Gtk.TreeView" id="reagentListView">
 
                                <property name="MemberName" />
 
                                <property name="WidthRequest">300</property>
 
                                <property name="CanFocus">True</property>
 
                              </widget>
 
                            </child>
 
                          </widget>
 
                        </child>
 
                      </widget>
 
                    </child>
 
                    <child>
 
                      <widget class="Gtk.Label" id="GtkLabel4">
 
                        <property name="MemberName" />
 
                        <property name="LabelProp" translatable="yes">&lt;b&gt;Ingredients&lt;/b&gt;</property>
 
                        <property name="UseMarkup">True</property>
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">9</property>
 
                        <property name="type">label_item</property>
 
                      </packing>
 
                    </child>
 
                  </widget>
 
                  <packing>
 
                    <property name="PackType">End</property>
 
                    <property name="Position">7</property>
 
                    <property name="AutoSize">True</property>
 
                  </packing>
 
                </child>
 
                <child>
 
                  <widget class="Gtk.HSeparator" id="hseparator6">
 
                    <property name="MemberName" />
 
                  </widget>
 
                  <packing>
 
                    <property name="PackType">End</property>
 
                    <property name="Position">8</property>
 
                    <property name="AutoSize">True</property>
...
 
@@ -1398,35 +1516,10 @@ You can either import an existing Practi
 
                    <child>
 
                      <widget class="Gtk.Alignment" id="GtkAlignment">
 
                      <widget class="Gtk.ScrolledWindow" id="GtkScrolledWindow">
 
                        <property name="MemberName" />
 
                        <property name="Xalign">0</property>
 
                        <property name="Yalign">0</property>
 
                        <property name="LeftPadding">12</property>
 
                        <child>
 
                          <widget class="Gtk.ScrolledWindow" id="scrolledwindow1">
 
                            <property name="MemberName" />
 
                            <property name="CanFocus">True</property>
 
                            <property name="ShadowType">In</property>
 
                            <child>
 
                              <widget class="Gtk.Viewport" id="GtkViewport">
 
                                <property name="MemberName" />
 
                                <property name="ShadowType">None</property>
 
                                <child>
 
                                  <widget class="Gtk.VBox" id="recipeListBox">
 
                          <widget class="Gtk.TreeView" id="recipeIngredientsView">
 
                                    <property name="MemberName" />
 
                                    <property name="Homogeneous">True</property>
 
                                    <property name="Spacing">6</property>
 
                                    <property name="BorderWidth">1</property>
 
                                    <child>
 
                                      <placeholder />
 
                                    </child>
 
                                    <child>
 
                                      <placeholder />
 
                                    </child>
 
                                    <child>
 
                                      <placeholder />
 
                                    </child>
 
                                  </widget>
 
                                </child>
 
                              </widget>
 
                            </child>
 
                            <property name="CanFocus">True</property>
 
                            <property name="ShowScrollbars">True</property>
 
                          </widget>
...
 
@@ -1452,2 +1545,18 @@ You can either import an existing Practi
 
                <child>
 
                  <widget class="Gtk.Button" id="button919">
 
                    <property name="MemberName" />
 
                    <property name="CanFocus">True</property>
 
                    <property name="Type">TextOnly</property>
 
                    <property name="Label" translatable="yes">Copy</property>
 
                    <property name="UseUnderline">True</property>
 
                    <signal name="Clicked" handler="OnCopyRecipeToClipboard" />
 
                  </widget>
 
                  <packing>
 
                    <property name="Position">1</property>
 
                    <property name="AutoSize">True</property>
 
                    <property name="Expand">False</property>
 
                    <property name="Fill">False</property>
 
                  </packing>
 
                </child>
 
                <child>
 
                  <widget class="DesertPaintLab.PaintSwatch" id="paintSwatch">
...
 
@@ -1458,3 +1567,3 @@ You can either import an existing Practi
 
                  <packing>
 
                    <property name="Position">1</property>
 
                    <property name="Position">2</property>
 
                    <property name="AutoSize">True</property>
0 comments (0 inline, 0 general)