Beispiel #1
0
        //Returns any nodes that are created
        public IEnumerable <ProductionNode> CreateOrLinkAllPossibleSupplyNodes(ProductionNode node)
        {
            List <ProductionNode> createdNodes = new List <ProductionNode>();

            var unlinkedItems = node.Inputs.Where(i => !node.InputLinks.Any(nl => nl.Item == i));

            foreach (Item item in unlinkedItems)
            {
                var existingNodes = Nodes.OfType <SupplyNode>().Where(n => n.SuppliedItem == item);

                if (!existingNodes.Any())
                {
                    SupplyNode newNode = SupplyNode.Create(item, this);
                    NodeLink.Create(newNode, node, item);
                    createdNodes.Add(newNode);
                }
                else
                {
                    foreach (SupplyNode existingNode in existingNodes)
                    {
                        NodeLink.Create(existingNode, node, item);
                    }
                }
            }
            return(createdNodes);
        }
Beispiel #2
0
        public void AutoSatisfyNodeDemand(ProductionNode node, Item item)
        {
            if (node.InputLinks.Any(l => l.Item == item))               //Increase throughput of existing node link
            {
                NodeLink link = node.InputLinks.First(l => l.Item == item);
                //link.Amount += node.GetExcessDemand(item);
            }
            else if (Nodes.Any(n => n.Outputs.Contains(item)))                  //Add link from existing node
            {
                ProductionNode existingNode = Nodes.Find(n => n.Outputs.Contains(item));
                NodeLink.Create(existingNode, node, item);
            }
            else if (item.Recipes.Any(r => !CyclicRecipes.Contains(r)))                 //Create new recipe node and link from it
            {
                RecipeNode newNode = RecipeNode.Create(item.Recipes.First(r => !CyclicRecipes.Contains(r)), this);
                NodeLink.Create(newNode, node, item);
            }
            else                //Create new supply node and link from it
            {
                SupplyNode newNode = SupplyNode.Create(item, this);
                NodeLink.Create(newNode, node, item, node.GetUnsatisfiedDemand(item));
            }

            ReplaceCycles();
        }
Beispiel #3
0
        public static SupplyNode Create(Item item, ProductionGraph graph)
        {
            SupplyNode node = new SupplyNode(item, graph);

            node.Graph.Nodes.Add(node);
            node.Graph.InvalidateCaches();
            return(node);
        }
Beispiel #4
0
        private void AddItemButton_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem lvItem in ItemListView.SelectedItems)
            {
                Item        item       = (Item)lvItem.Tag;
                NodeElement newElement = null;

                var itemSupplyOption = new ItemChooserControl(item, "Create infinite supply node", item.FriendlyName);
                var itemOutputOption = new ItemChooserControl(item, "Create output node", item.FriendlyName);

                var optionList = new List <ChooserControl>();
                optionList.Add(itemOutputOption);
                foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Enabled))
                {
                    if (recipe.Results.ContainsKey(item))
                    {
                        optionList.Add(new RecipeChooserControl(recipe, String.Format("Create '{0}' recipe node", recipe.FriendlyName), recipe.FriendlyName));
                    }
                }
                optionList.Add(itemSupplyOption);

                foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Enabled))
                {
                    if (recipe.Ingredients.ContainsKey(item))
                    {
                        optionList.Add(new RecipeChooserControl(recipe, String.Format("Create '{0}' recipe node", recipe.FriendlyName), recipe.FriendlyName));
                    }
                }

                var chooserPanel = new ChooserPanel(optionList, GraphViewer);

                Point location = GraphViewer.ScreenToGraph(new Point(GraphViewer.Width / 2, GraphViewer.Height / 2));

                chooserPanel.Show(c =>
                {
                    if (c != null)
                    {
                        if (c == itemSupplyOption)
                        {
                            newElement = new NodeElement(SupplyNode.Create(item, GraphViewer.Graph), GraphViewer);
                        }
                        else if (c is RecipeChooserControl)
                        {
                            newElement = new NodeElement(RecipeNode.Create((c as RecipeChooserControl).DisplayedRecipe, GraphViewer.Graph), GraphViewer);
                        }
                        else if (c == itemOutputOption)
                        {
                            newElement = new NodeElement(ConsumerNode.Create(item, GraphViewer.Graph), GraphViewer);
                        }

                        newElement.Update();
                        newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                    }
                });
            }

            GraphViewer.Graph.UpdateNodeValues();
        }
Beispiel #5
0
        public NodeElement(ProductionNode displayedNode, ProductionGraphViewModel parent)
        {
            Parent = parent;
            HorizontalAlignment = HorizontalAlignment.Center;
            VerticalAlignment   = VerticalAlignment.Center;
            DisplayedNode       = displayedNode;
            Initialize(displayedNode);

            BackgroundColor = DisplayedNode switch {
                ConsumerNode consumer => consumer.ConsumedItem.IsMissingItem ? MissingColor : SupplyColor,
                SupplyNode supplier => supplier.SuppliedItem.IsMissingItem ? MissingColor : ConsumerColor,
                RecipeNode recipe => recipe.BaseRecipe.IsMissingRecipe ? MissingColor : RecipeColor,
                PassthroughNode passthrough => passthrough.PassedItem.IsMissingItem
                    ? MissingColor
                    : PassthroughColor,
                             _ => throw new ArgumentException("No branch for node: " + DisplayedNode)
            };
        }
Beispiel #6
0
        public void LoadFromJson(JObject json)
        {
            Graph.Nodes.Clear();
            Elements.Clear();

            //Has to go first, as all other data depends on which mods are loaded
            List <String> EnabledMods = json["EnabledMods"].Select(t => (String)t).ToList();

            foreach (Mod mod in DataCache.Mods)
            {
                mod.Enabled = EnabledMods.Contains(mod.Name);
            }
            List <String> enabledMods = DataCache.Mods.Where(m => m.Enabled).Select(m => m.Name).ToList();


            using (ProgressForm form = new ProgressForm(enabledMods))
            {
                form.ShowDialog();
            }

            Graph.SelectedAmountType = (AmountType)(int)json["AmountType"];
            Graph.SelectedUnit       = (RateUnit)(int)json["Unit"];

            List <JToken> nodes = json["Nodes"].ToList <JToken>();

            foreach (var node in nodes)
            {
                ProductionNode newNode = null;

                switch ((String)node["NodeType"])
                {
                case "Consumer":
                {
                    String itemName = (String)node["ItemName"];
                    if (DataCache.Items.ContainsKey(itemName))
                    {
                        Item item = DataCache.Items[itemName];
                        newNode = ConsumerNode.Create(item, Graph);
                    }
                    else
                    {
                        Item missingItem = new Item(itemName);
                        missingItem.IsMissingItem = true;
                        newNode = ConsumerNode.Create(missingItem, Graph);
                    }
                    break;
                }

                case "Supply":
                {
                    String itemName = (String)node["ItemName"];
                    if (DataCache.Items.ContainsKey(itemName))
                    {
                        Item item = DataCache.Items[itemName];
                        newNode = SupplyNode.Create(item, Graph);
                    }
                    else
                    {
                        Item missingItem = new Item(itemName);
                        missingItem.IsMissingItem = true;
                        DataCache.Items.Add(itemName, missingItem);
                        newNode = SupplyNode.Create(missingItem, Graph);
                    }
                    break;
                }

                case "PassThrough":
                {
                    String itemName = (String)node["ItemName"];
                    if (DataCache.Items.ContainsKey(itemName))
                    {
                        Item item = DataCache.Items[itemName];
                        newNode = PassthroughNode.Create(item, Graph);
                    }
                    else
                    {
                        Item missingItem = new Item(itemName);
                        missingItem.IsMissingItem = true;
                        DataCache.Items.Add(itemName, missingItem);
                        newNode = PassthroughNode.Create(missingItem, Graph);
                    }
                    break;
                }

                case "Recipe":
                {
                    String recipeName = (String)node["RecipeName"];
                    if (DataCache.Recipes.ContainsKey(recipeName))
                    {
                        Recipe recipe = DataCache.Recipes[recipeName];
                        newNode = RecipeNode.Create(recipe, Graph);
                    }
                    else
                    {
                        Recipe missingRecipe = new Recipe(recipeName, 0f, new Dictionary <Item, float>(), new Dictionary <Item, float>());
                        missingRecipe.IsMissingRecipe = true;
                        DataCache.Recipes.Add(recipeName, missingRecipe);
                        newNode = RecipeNode.Create(missingRecipe, Graph);
                    }

                    if (node["Assembler"] != null)
                    {
                        var assemblerKey = (String)node["Assembler"];
                        if (DataCache.Assemblers.ContainsKey(assemblerKey))
                        {
                            (newNode as RecipeNode).Assembler = DataCache.Assemblers[assemblerKey];
                        }
                    }

                    (newNode as RecipeNode).NodeModules = ModuleSelector.Load(node);
                    break;
                }

                default:
                {
                    Trace.Fail("Unknown node type: " + node["NodeType"]);
                    break;
                }
                }

                if (newNode != null)
                {
                    newNode.rateType = (RateType)(int)node["RateType"];
                    if (newNode.rateType == RateType.Manual)
                    {
                        if (node["DesiredRate"] != null)
                        {
                            newNode.desiredRate = (float)node["DesiredRate"];
                        }
                        else
                        {
                            // Legacy data format stored desired rate in actual
                            newNode.desiredRate = (float)node["ActualRate"];
                        }
                    }
                    if (node["SpeedBonus"] != null)
                    {
                        newNode.SpeedBonus = Math.Round((float)node["SpeedBonus"], 4);
                    }
                    if (node["ProductivityBonus"] != null)
                    {
                        newNode.ProductivityBonus = Math.Round((float)node["ProductivityBonus"], 4);
                    }
                }
            }

            List <JToken> nodeLinks = json["NodeLinks"].ToList <JToken>();

            foreach (var nodelink in nodeLinks)
            {
                ProductionNode supplier = Graph.Nodes[(int)nodelink["Supplier"]];
                ProductionNode consumer = Graph.Nodes[(int)nodelink["Consumer"]];

                String itemName = (String)nodelink["Item"];
                if (!DataCache.Items.ContainsKey(itemName))
                {
                    Item missingItem = new Item(itemName);
                    missingItem.IsMissingItem = true;
                    DataCache.Items.Add(itemName, missingItem);
                }
                Item item = DataCache.Items[itemName];
                NodeLink.Create(supplier, consumer, item);
            }

            IEnumerable <String> EnabledAssemblers = json["EnabledAssemblers"].Select(t => (String)t);

            foreach (Assembler assembler in DataCache.Assemblers.Values)
            {
                assembler.Enabled = EnabledAssemblers.Contains(assembler.Name);
            }

            IEnumerable <String> EnabledMiners = json["EnabledMiners"].Select(t => (String)t);

            foreach (Miner miner in DataCache.Miners.Values)
            {
                miner.Enabled = EnabledMiners.Contains(miner.Name);
            }

            IEnumerable <String> EnabledModules = json["EnabledModules"].Select(t => (String)t);

            foreach (Module module in DataCache.Modules.Values)
            {
                module.Enabled = EnabledModules.Contains(module.Name);
            }

            JToken enabledRecipesToken;

            if (json.TryGetValue("EnabledRecipes", out enabledRecipesToken))
            {
                IEnumerable <String> EnabledRecipes = enabledRecipesToken.Select(t => (String)t);
                foreach (Recipe recipe in DataCache.Recipes.Values)
                {
                    recipe.Enabled = EnabledRecipes.Contains(recipe.Name);
                }
            }

            Graph.UpdateNodeValues();
            AddRemoveElements();

            List <String> ElementLocations = json["ElementLocations"].Select(l => (String)l).ToList();

            for (int i = 0; i < ElementLocations.Count; i++)
            {
                int[]        splitPoint = ElementLocations[i].Split(',').Select(s => Convert.ToInt32(s)).ToArray();
                GraphElement element    = GetElementForNode(Graph.Nodes[i]);
                element.Location = new Point(splitPoint[0], splitPoint[1]);
            }

            LimitViewToBounds();
        }
Beispiel #7
0
        void HandleItemDropping(object sender, DragEventArgs e)
        {
            if (GhostDragElement != null)
            {
                if (e.Data.GetDataPresent(typeof(HashSet <Item>)))
                {
                    foreach (Item item in GhostDragElement.Items)
                    {
                        NodeElement newElement = null;

                        var itemSupplyOption      = new ItemChooserControl(item, "Create infinite supply node", item.FriendlyName);
                        var itemOutputOption      = new ItemChooserControl(item, "Create output node", item.FriendlyName);
                        var itemPassthroughOption = new ItemChooserControl(item, "Create pass-through node", item.FriendlyName);

                        var optionList = new List <ChooserControl>();
                        optionList.Add(itemPassthroughOption);
                        optionList.Add(itemOutputOption);
                        foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Enabled))
                        {
                            if (recipe.Results.ContainsKey(item) && recipe.Category != "incinerator" && recipe.Category != "incineration")
                            {
                                optionList.Add(new RecipeChooserControl(recipe, String.Format("Create '{0}' recipe node", recipe.FriendlyName), recipe.FriendlyName));
                            }
                        }
                        optionList.Add(itemSupplyOption);

                        var chooserPanel = new ChooserPanel(optionList, this);

                        Point location = GhostDragElement.Location;

                        chooserPanel.Show(c =>
                        {
                            if (c != null)
                            {
                                if (c == itemSupplyOption)
                                {
                                    newElement = new NodeElement(SupplyNode.Create(item, this.Graph), this);
                                }
                                else if (c is RecipeChooserControl)
                                {
                                    newElement = new NodeElement(RecipeNode.Create((c as RecipeChooserControl).DisplayedRecipe, this.Graph), this);
                                }
                                else if (c == itemPassthroughOption)
                                {
                                    newElement = new NodeElement(PassthroughNode.Create(item, this.Graph), this);
                                }
                                else if (c == itemOutputOption)
                                {
                                    newElement = new NodeElement(ConsumerNode.Create(item, this.Graph), this);
                                }
                                else
                                {
                                    Trace.Fail("No handler for selected item");
                                }

                                Graph.UpdateNodeValues();
                                newElement.Update();
                                newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                            }
                        });
                    }
                }
                else if (e.Data.GetDataPresent(typeof(HashSet <Recipe>)))
                {
                    foreach (Recipe recipe in GhostDragElement.Recipes)
                    {
                        NodeElement newElement = new NodeElement(RecipeNode.Create(recipe, Graph), this);
                        Graph.UpdateNodeValues();
                        newElement.Update();
                        newElement.Location = Point.Add(GhostDragElement.Location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                    }
                }

                GhostDragElement.Dispose();
            }
        }
Beispiel #8
0
		public static SupplyNode Create(Item item, ProductionGraph graph)
		{
			SupplyNode node = new SupplyNode(item, graph);
			node.Graph.Nodes.Add(node);
			node.Graph.InvalidateCaches();
			return node;
		}
Beispiel #9
0
        private void EndDrag(Point location)
        {
            if (SupplierElement != null && ConsumerElement != null)
            {
                if (StartConnectionType == LinkType.Input)
                {
                    NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item);
                }
                else
                {
                    NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item);
                }
            }
            else if (StartConnectionType == LinkType.Output && ConsumerElement == null)
            {
                List <ChooserControl> recipeOptionList = new List <ChooserControl>();

                var itemOutputOption      = new ItemChooserControl(Item, "Create output node", Item.FriendlyName);
                var itemPassthroughOption = new ItemChooserControl(Item, "Create pass-through node", Item.FriendlyName);

                recipeOptionList.Add(itemOutputOption);
                recipeOptionList.Add(itemPassthroughOption);

                foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Ingredients.Keys.Contains(Item) && r.Enabled && r.Category != "incinerator" && r.Category != "incineration"))
                {
                    recipeOptionList.Add(new RecipeChooserControl(recipe, "Use recipe " + recipe.FriendlyName, recipe.FriendlyName));
                }

                var chooserPanel = new ChooserPanel(recipeOptionList, Parent);
                chooserPanel.Show(c =>
                {
                    if (c != null)
                    {
                        NodeElement newElement = null;
                        if (c is RecipeChooserControl)
                        {
                            Recipe selectedRecipe = (c as RecipeChooserControl).DisplayedRecipe;
                            newElement            = new NodeElement(RecipeNode.Create(selectedRecipe, Parent.Graph), Parent);
                        }
                        else if (c == itemOutputOption)
                        {
                            Item selectedItem = (c as ItemChooserControl).DisplayedItem;
                            newElement        = new NodeElement(ConsumerNode.Create(selectedItem, Parent.Graph), Parent);
                            (newElement.DisplayedNode as ConsumerNode).rateType = RateType.Auto;
                        }
                        else if (c == itemPassthroughOption)
                        {
                            Item selectedItem = (c as ItemChooserControl).DisplayedItem;
                            newElement        = new NodeElement(PassthroughNode.Create(selectedItem, Parent.Graph), Parent);
                            (newElement.DisplayedNode as PassthroughNode).rateType = RateType.Auto;
                        }
                        else
                        {
                            Trace.Fail("Unhandled option: " + c.ToString());
                        }

                        newElement.Update();
                        newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                        new LinkElement(Parent, NodeLink.Create(SupplierElement.DisplayedNode, newElement.DisplayedNode, Item));
                    }

                    Parent.Graph.UpdateNodeValues();
                    Parent.AddRemoveElements();
                    Parent.UpdateNodes();
                });
            }
            else if (StartConnectionType == LinkType.Input && SupplierElement == null)
            {
                List <ChooserControl> recipeOptionList = new List <ChooserControl>();

                var itemSupplyOption      = new ItemChooserControl(Item, "Create infinite supply node", Item.FriendlyName);
                var itemPassthroughOption = new ItemChooserControl(Item, "Create pass-through node", Item.FriendlyName);

                recipeOptionList.Add(itemSupplyOption);
                recipeOptionList.Add(itemPassthroughOption);

                foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Results.Keys.Contains(Item) && r.Enabled && r.Category != "incinerator" && r.Category != "incineration"))
                {
                    if (recipe.Category != "incinerator" && recipe.Category != "incineration")
                    {
                        recipeOptionList.Add(new RecipeChooserControl(recipe, "Use recipe " + recipe.FriendlyName, recipe.FriendlyName));
                    }
                }

                var chooserPanel = new ChooserPanel(recipeOptionList, Parent);

                chooserPanel.Show(c =>
                {
                    if (c != null)
                    {
                        NodeElement newElement = null;
                        if (c is RecipeChooserControl)
                        {
                            Recipe selectedRecipe = (c as RecipeChooserControl).DisplayedRecipe;
                            newElement            = new NodeElement(RecipeNode.Create(selectedRecipe, Parent.Graph), Parent);
                        }
                        else if (c == itemSupplyOption)
                        {
                            Item selectedItem = (c as ItemChooserControl).DisplayedItem;
                            newElement        = new NodeElement(SupplyNode.Create(selectedItem, Parent.Graph), Parent);
                        }
                        else if (c == itemPassthroughOption)
                        {
                            Item selectedItem = (c as ItemChooserControl).DisplayedItem;
                            newElement        = new NodeElement(PassthroughNode.Create(selectedItem, Parent.Graph), Parent);
                            (newElement.DisplayedNode as PassthroughNode).rateType = RateType.Auto;
                        }
                        else
                        {
                            Trace.Fail("Unhandled option: " + c.ToString());
                        }
                        newElement.Update();
                        newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                        new LinkElement(Parent, NodeLink.Create(newElement.DisplayedNode, ConsumerElement.DisplayedNode, Item));
                    }

                    Parent.Graph.UpdateNodeValues();
                    Parent.AddRemoveElements();
                    Parent.UpdateNodes();
                });
            }

            Parent.Graph.UpdateNodeValues();
            Parent.AddRemoveElements();
            Parent.UpdateNodes();
            Dispose();
        }
Beispiel #10
0
        private void EndDrag(Point location)
        {
            if (SupplierElement != null && ConsumerElement != null)
            {
                if (StartConnectionType == LinkType.Input)
                {
                    NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item, ConsumerElement.DisplayedNode.GetUnsatisfiedDemand(Item));
                }
                else
                {
                    NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item, SupplierElement.DisplayedNode.GetExcessOutput(Item));
                }
            }
            else if (StartConnectionType == LinkType.Output && ConsumerElement == null)
            {
                using (var form = new RecipeChooserForm(DataCache.Recipes.Values.Where(r => r.Ingredients.Keys.Contains(Item)), new List <Item> {
                    Item
                }, "Create output node", "Use recipe {0}"))
                {
                    var result = form.ShowDialog();
                    if (result == DialogResult.OK)
                    {
                        NodeElement newElement = null;
                        if (form.selectedRecipe != null)
                        {
                            newElement = new NodeElement(RecipeNode.Create(form.selectedRecipe, Parent.Graph), Parent);
                        }
                        else if (form.selectedItem != null)
                        {
                            newElement = new NodeElement(ConsumerNode.Create(form.selectedItem, Parent.Graph), Parent);
                        }
                        newElement.Update();
                        newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                        new LinkElement(Parent, NodeLink.Create(SupplierElement.DisplayedNode, newElement.DisplayedNode, Item));
                    }
                }
            }
            else if (StartConnectionType == LinkType.Input && SupplierElement == null)
            {
                using (var form = new RecipeChooserForm(DataCache.Recipes.Values.Where(r => r.Results.Keys.Contains(Item)), new List <Item> {
                    Item
                }, "Create infinite supply node", "Use recipe {0}"))
                {
                    var result = form.ShowDialog();
                    if (result == DialogResult.OK)
                    {
                        NodeElement newElement = null;
                        if (form.selectedRecipe != null)
                        {
                            newElement = new NodeElement(RecipeNode.Create(form.selectedRecipe, Parent.Graph), Parent);
                        }
                        else if (form.selectedItem != null)
                        {
                            newElement = new NodeElement(SupplyNode.Create(form.selectedItem, Parent.Graph), Parent);
                        }
                        newElement.Update();
                        newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
                        new LinkElement(Parent, NodeLink.Create(newElement.DisplayedNode, ConsumerElement.DisplayedNode, Item));
                    }
                }
            }

            Parent.AddRemoveElements();
            Parent.UpdateNodes();
            Dispose();
        }
Beispiel #11
0
        public void CreateSupplyNodeToSatisfyItemDemand(ProductionNode node, Item item)
        {
            SupplyNode newNode = SupplyNode.Create(item, node.Graph);

            NodeLink.Create(newNode, node, item, node.GetUnsatisfiedDemand(item));
        }
Beispiel #12
0
        public void Update()
        {
            UpdateTabOrder();

            if (DisplayedNode is SupplyNode)
            {
                SupplyNode node = (SupplyNode)DisplayedNode;
                if (!Parent.ShowMiners)
                {
                    if (node.SuppliedItem.IsMissingItem)
                    {
                        text = String.Format("Item not loaded! ({0})", node.DisplayName);
                    }
                    else
                    {
                        text = "Input: " + node.SuppliedItem.FriendlyName;
                    }
                }
                else
                {
                    text = "";
                }
            }
            else if (DisplayedNode is ConsumerNode)
            {
                ConsumerNode node = (ConsumerNode)DisplayedNode;
                if (node.ConsumedItem.IsMissingItem)
                {
                    text = String.Format("Item not loaded! ({0})", node.DisplayName);
                }
                else
                {
                    text = "Output: " + node.ConsumedItem.FriendlyName;
                }
            }
            else if (DisplayedNode is RecipeNode)
            {
                RecipeNode node = (RecipeNode)DisplayedNode;
                if (!Parent.ShowAssemblers)
                {
                    if (node.BaseRecipe.IsMissingRecipe)
                    {
                        text = String.Format("Recipe not loaded! ({0})", node.DisplayName);
                    }
                    else
                    {
                        text = "Recipe: " + node.BaseRecipe.FriendlyName;
                    }
                }
                else
                {
                    text = "";
                }
            }

            Graphics graphics = Parent.CreateGraphics();
            int      minWidth = (int)graphics.MeasureString(text, size10Font).Width;

            Width = Math.Max(75, getIconWidths());
            Width = Math.Max(Width, minWidth);

            if (assemblerBox != null)
            {
                if ((DisplayedNode is RecipeNode && Parent.ShowAssemblers) ||
                    (DisplayedNode is SupplyNode && Parent.ShowMiners))
                {
                    Height = 120;
                    if (DisplayedNode is RecipeNode)
                    {
                        var assemblers = (DisplayedNode as RecipeNode).GetAssemblers();
                        if (Parent.Graph.SelectedAmountType == AmountType.FixedAmount)
                        {
                            assemblers = assemblers.ToDictionary(p => p.Key, p => 0);
                        }
                        assemblerBox.AssemblerList = assemblers;
                    }
                    else if (DisplayedNode is SupplyNode)
                    {
                        assemblerBox.AssemblerList = (DisplayedNode as SupplyNode).GetMinimumMiners();
                    }
                    assemblerBox.Update();
                    Width          = Math.Max(Width, assemblerBox.Width + 20);
                    Height         = assemblerBox.Height + 80;
                    assemblerBox.X = (Width - assemblerBox.Width) / 2 + 2;
                    assemblerBox.Y = (Height - assemblerBox.Height) / 2 + 2;
                }
                else
                {
                    assemblerBox.AssemblerList.Clear();
                    Width  = Math.Max(100, Width);
                    Height = 90;
                    assemblerBox.Update();
                }
            }

            else
            {
                Height = 90;
            }

            foreach (ItemTab tab in inputTabs.Union(outputTabs))
            {
                tab.FillColour = chooseIconColour(tab.Item, tab.Type);
                tab.Text       = getIconString(tab.Item, tab.Type);
            }

            UpdateTabOrder();
        }