From 56d70f5592dca2fd0d4f5e6c3b10dae2816fbca5 Mon Sep 17 00:00:00 2001 From: Omar Tawfik Date: Sat, 6 Nov 2021 17:04:34 -0700 Subject: [PATCH] implement node flipping --- Foreman/Models/Nodes/BaseNode.cs | 4 ++++ Foreman/Models/Nodes/ConsumerNode.cs | 1 + Foreman/Models/Nodes/PassthroughNode.cs | 1 + Foreman/Models/Nodes/RecipeNode.cs | 15 ++++++++------- Foreman/Models/Nodes/SupplierNode.cs | 1 + Foreman/Models/ProductionGraph.cs | 10 ++++++++++ .../Elements/BaseLinkElement.cs | 16 ++++++++++++++-- .../Elements/BaseNodeElement.cs | 17 +++++++++++++++-- .../Elements/ItemTabElement.cs | 7 +++++-- .../ProductionGraphView/Elements/LinkElement.cs | 10 +++++++++- .../ProductionGraphViewer.cs | 5 +++++ 11 files changed, 73 insertions(+), 14 deletions(-) diff --git a/Foreman/Models/Nodes/BaseNode.cs b/Foreman/Models/Nodes/BaseNode.cs index 1e494ad8..761bcff8 100644 --- a/Foreman/Models/Nodes/BaseNode.cs +++ b/Foreman/Models/Nodes/BaseNode.cs @@ -23,6 +23,8 @@ public abstract partial class BaseNode : ISerializable private RateType rateType; public RateType RateType { get { return rateType; } set { if (rateType != value) { rateType = value; UpdateState(); } } } + public bool IsFlipped { get; set; } + public double ActualRatePerSec { get; private set; } private double desiredRatePerSec; @@ -122,6 +124,8 @@ public abstract class ReadOnlyBaseNode public double DesiredRate => MyNode.DesiredRate; public NodeState State => MyNode.State; + public bool IsFlipped => MyNode.IsFlipped; + public abstract List GetErrors(); public abstract List GetWarnings(); diff --git a/Foreman/Models/Nodes/ConsumerNode.cs b/Foreman/Models/Nodes/ConsumerNode.cs index 223a11a5..12290b3a 100644 --- a/Foreman/Models/Nodes/ConsumerNode.cs +++ b/Foreman/Models/Nodes/ConsumerNode.cs @@ -46,6 +46,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("RateType", RateType); if (RateType == RateType.Manual) info.AddValue("DesiredRate", DesiredRatePerSec); + info.AddValue("IsFlipped", IsFlipped); } public override string ToString() { return string.Format("Consumption node for: {0}", ConsumedItem.Name); } diff --git a/Foreman/Models/Nodes/PassthroughNode.cs b/Foreman/Models/Nodes/PassthroughNode.cs index e2d61aac..3316d244 100644 --- a/Foreman/Models/Nodes/PassthroughNode.cs +++ b/Foreman/Models/Nodes/PassthroughNode.cs @@ -45,6 +45,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("RateType", RateType); if (RateType == RateType.Manual) info.AddValue("DesiredRate", DesiredRatePerSec); + info.AddValue("IsFlipped", IsFlipped); } public override string ToString() { return string.Format("Passthrough node for: {0}", PassthroughItem.Name); } diff --git a/Foreman/Models/Nodes/RecipeNode.cs b/Foreman/Models/Nodes/RecipeNode.cs index 371321ca..7c6e2fdc 100644 --- a/Foreman/Models/Nodes/RecipeNode.cs +++ b/Foreman/Models/Nodes/RecipeNode.cs @@ -359,6 +359,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("BeaconsPerAssembler", BeaconsPerAssembler); info.AddValue("BeaconsConst", BeaconsConst); } + info.AddValue("IsFlipped", IsFlipped); } public override string ToString() { return string.Format("Recipe node for: {0}", BaseRecipe.Name); } @@ -720,12 +721,12 @@ public override Dictionary GetWarningResolutions() resolutions.Add("Turn off beacon", new Action(() => SetBeacon(null))); if ((WarningSet & (RecipeNode.Warnings.BModuleIsDisabled | RecipeNode.Warnings.BModuleIsUnavailable)) != 0) - resolutions.Add("Remove error modules from beacon", new Action(() => - { - for (int i = MyNode.BeaconModules.Count - 1; i >= 0; i--) - if (!MyNode.BeaconModules[i].Enabled || !MyNode.BeaconModules[i].Available) - RemoveBeaconModule(i); - })); + resolutions.Add("Remove error modules from beacon", new Action(() => + { + for (int i = MyNode.BeaconModules.Count - 1; i >= 0; i--) + if (!MyNode.BeaconModules[i].Enabled || !MyNode.BeaconModules[i].Available) + RemoveBeaconModule(i); + })); if ((WarningSet & RecipeNode.Warnings.TemeratureFluidBurnerInvalidLinks) != 0) resolutions.Add("Remove fuel links", new Action(() => @@ -854,7 +855,7 @@ public void SetAssemblerModules(IEnumerable modules, bool filterModules) { MyNode.AssemblerModules.Clear(); if (modules != null) - { + { if(filterModules) { HashSet acceptableModules = new HashSet(MyNode.BaseRecipe.Modules.Intersect(MyNode.SelectedAssembler.Modules)); diff --git a/Foreman/Models/Nodes/SupplierNode.cs b/Foreman/Models/Nodes/SupplierNode.cs index 51a97f54..d388d008 100644 --- a/Foreman/Models/Nodes/SupplierNode.cs +++ b/Foreman/Models/Nodes/SupplierNode.cs @@ -45,6 +45,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("RateType", RateType); if (RateType == RateType.Manual) info.AddValue("DesiredRate", DesiredRatePerSec); + info.AddValue("IsFlipped", IsFlipped); } public override string ToString() { return string.Format("Supply node for: {0}", SuppliedItem.Name); } diff --git a/Foreman/Models/ProductionGraph.cs b/Foreman/Models/ProductionGraph.cs index d6103cfb..f054b94c 100644 --- a/Foreman/Models/ProductionGraph.cs +++ b/Foreman/Models/ProductionGraph.cs @@ -195,6 +195,12 @@ public void DeleteNode(ReadOnlyBaseNode node) NodeDeleted?.Invoke(this, new NodeEventArgs(node)); } + public void FlipNode(ReadOnlyBaseNode node) + { + BaseNode realNode = roToNode[node]; + realNode.IsFlipped = !realNode.IsFlipped; + } + public void DeleteNodes(IEnumerable nodes) { foreach (ReadOnlyBaseNode node in nodes) @@ -521,6 +527,10 @@ public NewNodeCollection InsertNodesFromJson(DataCache cache, JToken json) //cac newNode.DesiredRatePerSec = (double)nodeJToken["DesiredRate"]; } + + + newNode.IsFlipped = (bool)(nodeJToken["IsFlipped"] ?? false); + oldNodeIndices.Add((int)nodeJToken["NodeID"], newNode.ReadOnlyNode); } diff --git a/Foreman/ProductionGraphView/Elements/BaseLinkElement.cs b/Foreman/ProductionGraphView/Elements/BaseLinkElement.cs index 49ec2c8e..d2024938 100644 --- a/Foreman/ProductionGraphView/Elements/BaseLinkElement.cs +++ b/Foreman/ProductionGraphView/Elements/BaseLinkElement.cs @@ -42,7 +42,7 @@ public override void UpdateVisibility(Rectangle graph_zone, int xborder, int ybo } Visible = - CalculatedBounds.X + CalculatedBounds.Width > graph_zone.X - xborder && + CalculatedBounds.X + CalculatedBounds.Width > graph_zone.X - xborder && CalculatedBounds.X < graph_zone.X + graph_zone.Width + xborder && CalculatedBounds.Y + CalculatedBounds.Height > graph_zone.Y - yborder && CalculatedBounds.Y < graph_zone.Y + graph_zone.Height + yborder; @@ -107,8 +107,20 @@ protected override void Draw(Graphics graphics, bool simple) { UpdateCurve(); - using (Pen pen = new Pen(Item.AverageColor, LinkWidth) { EndCap = System.Drawing.Drawing2D.LineCap.Round, StartCap = System.Drawing.Drawing2D.LineCap.Round }) + using (Pen pen = new Pen(Item.AverageColor, LinkWidth)) { + + if (SupplierElement?.DisplayedNode.IsFlipped == true || ConsumerElement?.DisplayedNode.IsFlipped == true) + { + pen.CustomStartCap = new System.Drawing.Drawing2D.AdjustableArrowCap(LinkWidth, LinkWidth); + pen.EndCap = System.Drawing.Drawing2D.LineCap.Round; + } + else + { + pen.StartCap = System.Drawing.Drawing2D.LineCap.Round; + pen.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(LinkWidth, LinkWidth); + } + if (linkingUp) graphics.DrawBeziers(pen, new Point[] { pointN, diff --git a/Foreman/ProductionGraphView/Elements/BaseNodeElement.cs b/Foreman/ProductionGraphView/Elements/BaseNodeElement.cs index 92e1c957..20267101 100644 --- a/Foreman/ProductionGraphView/Elements/BaseNodeElement.cs +++ b/Foreman/ProductionGraphView/Elements/BaseNodeElement.cs @@ -118,18 +118,23 @@ private void UpdateTabOrder() InputTabs = InputTabs.OrderBy(it => GetItemTabXHeuristic(it)).ThenBy(it => it.Item.Name).ToList(); //then by ensures same result no matter who came first OutputTabs = OutputTabs.OrderBy(it => GetItemTabXHeuristic(it)).ThenBy(it => it.Item.Name).ToList(); + int topRow = (-Height / 2) + 1; + int bottomRow = (Height / 2) - 1; + int outputRow = DisplayedNode.IsFlipped ? bottomRow : topRow; + int inputRow = DisplayedNode.IsFlipped ? topRow : bottomRow; + int x = -GetIconWidths(OutputTabs) / 2; foreach (ItemTabElement tab in OutputTabs) { x += TabPadding; - tab.Location = new Point(x + (tab.Width / 2), (-Height / 2) + 1); + tab.Location = new Point(x + (tab.Width / 2), outputRow); x += tab.Width; } x = -GetIconWidths(InputTabs) / 2; foreach (ItemTabElement tab in InputTabs) { x += TabPadding; - tab.Location = new Point(x + (tab.Width / 2), (Height / 2) - 1); + tab.Location = new Point(x + (tab.Width / 2), inputRow); x += tab.Width; } } @@ -269,6 +274,14 @@ protected virtual void MouseUpAction(Point graph_point, MouseButtons button) graphViewer.Graph.DeleteNode(DisplayedNode); graphViewer.Graph.UpdateNodeValues(); }))); + RightClickMenu.Items.Add(new ToolStripMenuItem("Flip node", null, + new EventHandler((o, e) => + { + RightClickMenu.Close(); + graphViewer.Graph.FlipNode(DisplayedNode); + graphViewer.Graph.UpdateNodeValues(); + + }))); if (graphViewer.SelectedNodes.Count > 1 && graphViewer.SelectedNodes.Contains(this)) { RightClickMenu.Items.Add(new ToolStripMenuItem("Delete selected nodes", null, diff --git a/Foreman/ProductionGraphView/Elements/ItemTabElement.cs b/Foreman/ProductionGraphView/Elements/ItemTabElement.cs index 1200537e..770a022b 100644 --- a/Foreman/ProductionGraphView/Elements/ItemTabElement.cs +++ b/Foreman/ProductionGraphView/Elements/ItemTabElement.cs @@ -49,10 +49,13 @@ public ItemTabElement(Item item, LinkType type, ProductionGraphViewer graphViewe public Point GetConnectionPoint() //in graph coordinates { + int topRow = (-Height / 2); + int bottomRow = (Height / 2); + if (LinkType == LinkType.Input) - return LocalToGraph(new Point(0, Height / 2)); + return LocalToGraph(new Point(0, DisplayedNode.IsFlipped ? topRow : bottomRow)); else //if(LinkType == LinkType.Output) - return LocalToGraph(new Point(0, -Height / 2)); + return LocalToGraph(new Point(0, DisplayedNode.IsFlipped ? bottomRow : topRow)); } public void UpdateValues(double recipeRate, double suppliedRate, bool isOversupplied) //if input then: recipe rate = consume rate; if output then recipe rate = production rate diff --git a/Foreman/ProductionGraphView/Elements/LinkElement.cs b/Foreman/ProductionGraphView/Elements/LinkElement.cs index 1d677f08..5473f61b 100644 --- a/Foreman/ProductionGraphView/Elements/LinkElement.cs +++ b/Foreman/ProductionGraphView/Elements/LinkElement.cs @@ -36,7 +36,15 @@ protected override Point[] GetCurveEndpoints() { Point pointMupdate = ConsumerTab.GetConnectionPoint(); Point pointNupdate = SupplierTab.GetConnectionPoint(); - return new Point[] { pointMupdate, pointNupdate }; + + if (SupplierElement.DisplayedNode.IsFlipped || ConsumerElement.DisplayedNode.IsFlipped) + { + return new Point[] { pointNupdate, pointMupdate }; + } + else + { + return new Point[] { pointMupdate, pointNupdate }; + } } } } diff --git a/Foreman/ProductionGraphView/ProductionGraphViewer.cs b/Foreman/ProductionGraphView/ProductionGraphViewer.cs index 3fa5e63b..918444a7 100644 --- a/Foreman/ProductionGraphView/ProductionGraphViewer.cs +++ b/Foreman/ProductionGraphView/ProductionGraphViewer.cs @@ -238,6 +238,11 @@ public void AddRecipe(Point drawOrigin, Item baseItem, Point newLocation, NewNod break; } + if (originElement != null && originElement.DisplayedNode.IsFlipped != newNode.IsFlipped) + { + Graph.FlipNode(newNode); + } + //this is the offset to take into account multiple recipe additions (holding shift while selecting recipe). First node isnt shifted, all subsequent ones are 'attempted' to be spaced. //should be updated once the node graphics are updated (so that the node size doesnt depend as much on the text) BaseNodeElement newNodeElement = NodeElementDictionary[newNode];