public StreamTableControl(StreamPropertiesTable tableData, PFD.Streams.StreamControl parent, Workspace workspace, DrawingCanvas canvas) { InitializeComponent(); m_table = tableData; m_parent = parent; m_ws = workspace; m_canvas = canvas; // Do the initial UI setup HeaderTextBlock.Text = "Stream #" + m_table.Stream.Id.ToString(); Location = new Point(tableData.Location.X, tableData.Location.Y); UpdateUI(); // Ensure that the minimize button eats mouse events MinimizeButton.MouseLeftButtonDown += this.MinimizeButton_MouseButtonEvent; MinimizeButton.MouseLeftButtonUp += this.MinimizeButton_MouseButtonEvent; // Monitor changes in the parent stream (all we care about is the Id) m_table.Stream.PropertyChanged += this.Stream_PropertyChanged; // Monitor changes in the row data m_table.RowPropertyChanged += new PropertyChangedEventHandler(RowPropertyChanged); m_table.RowsChanged += new EventHandler(TableRowsChanged); // Monitor changes to the difficulty level so we can show/hide the temperature row // for chemical stream property tables m_ws.PropertyChanged += new PropertyChangedEventHandler(WorkspacePropertyChanged); // Monitor changes to m_table m_table.PropertyChanged += new PropertyChangedEventHandler(TablePropertyChanged); }
/// <summary> /// The member variable m_highlightedHover can be a reference to a process unit with a highlighted /// border or a stream with a specially colored stem line. This method removes either of these /// highlights and sets the member variable back to null. /// </summary> private void UnhighlightHover() { if (null == m_highlightedHover) { return; } ProcessUnitControl gpu = m_highlightedHover as ProcessUnitControl; if (null != gpu) { gpu.SetBorderColor(ProcessUnitBorderColor.NoBorder); } else { PFD.Streams.StreamControl s = m_highlightedHover as PFD.Streams.StreamControl; if (null != s) { s.Selected = true; s.Selected = false; } } m_highlightedHover = null; }
// Refactoring on this method is done (logic-wise, could use some cleanup otherwise) private static void DeleteHEWU(ProcessUnitControl he, DrawingCanvas canvas) { Workspace ws = canvas.GetWorkspace(); // Heat exchangers with utilities must also delete the heat stream that's incoming // Normally the heat stream is at index 0 among the incoming streams, but it seems like // this does not always hold true when loading from files so it's just safer to search // for it HeatStream heatStream = null; foreach (AbstractStream incomingStream in he.ProcessUnit.IncomingStreams) { if (incomingStream is HeatStream) { heatStream = incomingStream as HeatStream; break; } } PFD.Streams.StreamControl heatStreamControl = canvas.GetStreamControl(heatStream) as PFD.Streams.StreamControl; List <IUndoRedoAction> undos = new List <IUndoRedoAction>(); undos.Add(new Logic.Undos.AddToWorkspace(heatStream)); undos.Add(new Logic.Undos.AddToWorkspace(he.ProcessUnit)); // We need to check if the attached stream has a source if (null != heatStream.Source) { // Detach with undo undos.Add(new Logic.Undos.AttachOutgoingStream(heatStream.Source, heatStream)); heatStream.Source.DetachOutgoingStream(heatStream); } // Detach all outgoing streams and make undos foreach (AbstractStream s in he.ProcessUnit.OutgoingStreams) { undos.Add(new Logic.Undos.SetStreamSource(s, he.ProcessUnit, null, s.SourceLocation)); s.Source = null; } // Detach all incoming streams and make undos foreach (AbstractStream s in he.ProcessUnit.IncomingStreams) { undos.Add(new Logic.Undos.SetStreamDestination(s, he.ProcessUnit, null, s.DestinationLocation)); s.Destination = null; } ws.AddUndo(new UndoRedoCollection( "Undo deletion of heat exchanger with utility", undos.ToArray())); // Remove the stream and process unit from the workspace. Event handlers will update the UI. ws.RemoveStream(heatStream); ws.RemoveProcessUnit(he.ProcessUnit); }
public PFD.Streams.StreamControl GetStreamControl(AbstractStream stream) { foreach (UIElement uie in Children) { PFD.Streams.StreamControl s = uie as PFD.Streams.StreamControl; if (null != s) { if (Object.ReferenceEquals(s.Stream, stream)) { return(s); } } } return(null); }
public bool IsStreamEndpoint(UIElement element) { foreach (UIElement uie in Children) { PFD.Streams.StreamControl s = uie as PFD.Streams.StreamControl; if (s != null) { if (element == s.SourceDragIcon || element == s.DestinationDragIcon) { return(true); } } } return(false); }
private void Streams_CollectionChanged(object sender, EventArgs e) { // First go through all stream controls on the canvas and remove ones that are // no longer in the workspace. List <AbstractStream> streamsThatHaveControls = new List <AbstractStream>(); for (int i = 0; i < Children.Count; i++) { PFD.Streams.StreamControl stream = Children[i] as PFD.Streams.StreamControl; if (null == stream) { continue; } // Add it to a list that we'll use later streamsThatHaveControls.Add(stream.Stream); if (!m_workspace.Streams.Contains(stream.Stream)) { // Tell the stream control to remove itself and all it's children (stream lines, // comment sticky note controls, etc.) stream.RemoveSelfFromCanvas(this); // Reset the index since a bunch of child controls could have potentially just // been removed i = -1; } } // Now go through and add stream controls that are missing foreach (AbstractStream stream in m_workspace.Streams) { if (!streamsThatHaveControls.Contains(stream)) { PFD.Streams.StreamControl.CreateOnCanvas(this, stream); } } }
private void AddCommentCollectionMenuOptions(ContextMenu newContextMenu, string title) { // Make the header in the menu for the comment-specific options MenuItem menuItem = new MenuItem(); menuItem.Header = title; newContextMenu.Items.Add(menuItem); // We're using this item as a label, so don't let the user click it menuItem.IsHitTestVisible = false; // Change the colors to signal to the user that it's a label menuItem.Background = new SolidColorBrush(Colors.LightGray); menuItem.Foreground = new SolidColorBrush(Color.FromArgb(255, 100, 100, 100)); menuItem.FontWeight = FontWeights.Bold; menuItem = new MenuItem(); menuItem.Header = "Add new comment"; menuItem.Tag = m_canvas.SelectedElement; newContextMenu.Items.Add(menuItem); // Use an anonymous delegate to handle the click event menuItem.Click += delegate(object sender, RoutedEventArgs e) { MenuItem tempMI = sender as MenuItem; PFD.Streams.StreamControl stream = tempMI.Tag as PFD.Streams.StreamControl; ProcessUnitControl unit = tempMI.Tag as ProcessUnitControl; // Get a reference to the comment collection IList <StickyNote> comments; if (null != stream) { comments = stream.Stream.Comments; } else { comments = unit.ProcessUnit.Comments; } // Compute the location for the new comment MathCore.Vector location = StickyNoteControl.ComputeNewCommentNoteLocation( m_canvas, tempMI.Tag, 100.0, 100.0); // Create the new sticky note and add it to the workspace. Event handlers will update // the UI appropriately StickyNote sn = new StickyNote() { Width = 100.0, Height = 100.0, LocationX = location.X, LocationY = location.Y }; comments.Add(sn); // Add an undo that will remove the comment m_workspace.AddUndo(new UndoRedoCollection("Undo creation of comment", new RemoveComment(comments, comments.IndexOf(sn)))); // Make sure to remove the popup menu from the canvas m_canvas.Children.Remove(m_contextMenu); m_contextMenu = null; // Flip back to the default state for the canvas (null) m_canvas.CurrentState = null; }; string objName = "selected object"; if (m_canvas.SelectedElement is ProcessUnitControl) { objName = (m_canvas.SelectedElement as ProcessUnitControl).ProcessUnit.Label; } else if (m_canvas.SelectedElement is ChemProV.PFD.Streams.StreamControl) { objName = "selected stream"; } // Add a new menu item to hide all comments menuItem = new MenuItem(); menuItem.Header = "Hide all comments for " + objName; menuItem.Tag = m_canvas.SelectedElement; newContextMenu.Items.Add(menuItem); menuItem.Click += delegate(object sender, RoutedEventArgs e) { MenuItem tempMI = sender as MenuItem; (tempMI.Tag as UI.ICommentControlManager).HideAllComments(); // Make sure to remove the popup menu from the canvas m_canvas.Children.Remove(m_contextMenu); m_contextMenu = null; // Flip back to the default state for the canvas (null) m_canvas.CurrentState = null; }; // Add one to show all comments too menuItem = new MenuItem(); menuItem.Header = "Show all comments for " + objName; menuItem.Tag = m_canvas.SelectedElement; newContextMenu.Items.Add(menuItem); menuItem.Click += delegate(object sender, RoutedEventArgs e) { MenuItem tempMI = sender as MenuItem; (tempMI.Tag as UI.ICommentControlManager).ShowAllComments(); // Make sure to remove the popup menu from the canvas m_canvas.Children.Remove(m_contextMenu); m_contextMenu = null; // Flip back to the default state for the canvas (null) m_canvas.CurrentState = null; }; }
public void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { // If the canvas reference is null then we ignore mouse events if (null == m_canvas) { return; } // Here's where we need to flip over to the MovingStreamEndpoint state. We start by // finding out if we clicked on a process unit or not Point location = e.GetPosition(m_canvas); // Clear the border if we'd previously set one if (null != m_puWithAlteredBorderColor) { m_puWithAlteredBorderColor.SetBorderColor(ProcessUnitBorderColor.NoBorder); m_puWithAlteredBorderColor = null; } // Remove the floating icon m_canvas.RemoveChild(m_sourcePlacementIcon); m_sourcePlacementIcon = null; // Get a reference to the workspace Workspace ws = m_canvas.GetWorkspace(); // See if we clicked on a valid destination object ProcessUnitControl gpu = m_canvas.GetChildAt(location, m_sourcePlacementIcon) as ProcessUnitControl; if (null == gpu) { // This means that we clicked in an area where there's no process unit that we have // to attach to. m_stream.SourceLocation = new MathCore.Vector(location.X, location.Y); m_stream.DestinationLocation = m_stream.SourceLocation + (new MathCore.Vector(0, 20.0)); ws.AddStream(m_stream); // We need an undo to remove the stream that we just added. Note that we're going to switch // over to a different state below and that creates and undo as well. This is fine since // it allows you to undo the destination placement and stream creation separately. ws.AddUndo(new UndoRedoCollection("Undo stream creation", new Logic.Undos.RemoveStream(m_stream))); } else if (gpu.ProcessUnit.CanAcceptOutgoingStream(m_stream)) { // Setup the stream and add it to the workspace m_stream.SourceLocation = new MathCore.Vector(location.X, location.Y); m_stream.DestinationLocation = m_stream.SourceLocation + (new MathCore.Vector(0, 35.0)); m_stream.Source = gpu.ProcessUnit; ws.AddStream(m_stream); // Attach the outgoing stream to the process unit after we've added the stream to // the workspace gpu.ProcessUnit.AttachOutgoingStream(m_stream); // We've linked up the stream and added it to the workspace. Now create an undo that // does the opposite ws.AddUndo(new UndoRedoCollection("Undo stream creation", new Logic.Undos.DetachOutgoingStream(gpu.ProcessUnit, m_stream), new Logic.Undos.RemoveStream(m_stream))); } else { // This means we clicked on a process unit that we cannot connect to. In this case // we want to cancel everything. This is easy since we haven't modified the workspace, // so all we have to do it switch back to select mode. m_palette.SwitchToSelect(); return; } // Get the stream control that the DrawingCanvas should have added PFD.Streams.StreamControl streamControl = m_canvas.GetStreamControl(m_stream); // Tell it to hide the table streamControl.HideTable(); // Set references to null to indicate that this state should no longer process mouse input // messages after this. We are finishing up right here. DrawingCanvas c = m_canvas; m_canvas = null; m_stream = null; // Switch back to select mode m_palette.SwitchToSelect(); // Flip over to the state where we position the stream destination c.CurrentState = new MovingStreamEndpoint(streamControl.DestinationDragIcon, c, true); }
public static MathCore.Vector ComputeNewCommentNoteLocation(DrawingCanvas canvas, object parentControl, double controlWidth = 100.0, double controlHeight = 100.0) { // First resolve the "center point" of the parent object. Also get a reference to the collection // of comments. Point location; IList <StickyNote> comments; ProcessUnitControl lpu = parentControl as ProcessUnitControl; PFD.Streams.StreamControl stream = parentControl as PFD.Streams.StreamControl; if (null != lpu) { location = lpu.Location; comments = lpu.ProcessUnit.Comments; } else if (null != stream) { location = stream.StreamLineMidpoint; comments = stream.Stream.Comments; } else { throw new ArgumentException( "Parent control for a comment sticky note must be a stream or process unit " + "control.\n Method: ComputeNewCommentNoteLocation"); } // Get a reference to the workspace. We will look at other sticky notes in this workspace to // try to avoid direct overlap. Workspace ws = canvas.GetWorkspace(); MathCore.Vector loc; int attempts = 0; while (true) { // Compute a location double radius = 150.0; double angle = (double)(comments.Count % 6) * 60.0 / 180.0 * Math.PI; loc = new MathCore.Vector( location.X + radius * Math.Cos(angle), location.Y + radius * Math.Sin(angle)); // Make sure this location wouldn't make the control go off the canvas if (loc.X - (controlWidth / 2.0) < 0.0 || loc.Y - (controlHeight / 2.0) < 0.0) { attempts++; } else if ((null != stream && stream.Stream.ContainsCommentWithLocation(loc.X, loc.Y)) || (null != lpu && lpu.ProcessUnit.ContainsCommentWithLocation(loc.X, loc.Y))) { attempts++; } else { // This means the location is ok and we can return it return(loc); } // Try cascading if radial position failed if (attempts > 6) { // Reset attempts because we're about to try another method of positioning attempts = 0; double offset = 10.0; while (true) { loc.X = location.X + radius + offset; loc.Y = location.Y + offset; // Make sure this location wouldn't make the control go off the canvas if (loc.X - (controlWidth / 2.0) < 0.0 || loc.Y - (controlHeight / 2.0) < 0.0) { attempts++; } else if ((null != stream && stream.Stream.ContainsCommentWithLocation(loc.X, loc.Y)) || (null != lpu && lpu.ProcessUnit.ContainsCommentWithLocation(loc.X, loc.Y))) { attempts++; } else { // This means the location is ok and we can return it return(loc); } attempts++; if (attempts > 50) { // Just give up and choose an arbitrary position return(new MathCore.Vector(location.X + radius, location.Y)); } // Increase the offset for the next attempt offset += 10.0; } } } }
public UIElement GetChildAtIncludeStreams(Point location, params object[] excludeThese) { UIElement element = null; foreach (UIElement uie in Children) { // If it's in the exclusion list then ignore it if (null != excludeThese) { if (Array.IndexOf <object>(excludeThese, uie) >= 0) { continue; } } // If it's collapsed then ignore it if (System.Windows.Visibility.Collapsed == uie.Visibility) { continue; } double w = (double)uie.GetValue(Canvas.ActualWidthProperty); double h = (double)uie.GetValue(Canvas.ActualHeightProperty); double x = (double)uie.GetValue(Canvas.LeftProperty); double y = (double)uie.GetValue(Canvas.TopProperty); if (location.X >= x && location.X < x + w && location.Y >= y && location.Y < y + h) { // We found something at this location, but we need to check if we have another element // with a higher Z-index if (null != element) { if ((int)uie.GetValue(Canvas.ZIndexProperty) >= (int)element.GetValue(Canvas.ZIndexProperty)) { element = uie; } } else { element = uie; } } } // Check streams if we didn't get anything above if (null == element) { // We'll say any click within 4-pixels distance from the line is close enough double dist = 4.0; foreach (UIElement uie in Children) { // If it's in the exclusion list then ignore it if (null != excludeThese) { if (Array.IndexOf <object>(excludeThese, uie) >= 0) { continue; } } PFD.Streams.StreamControl stream = uie as PFD.Streams.StreamControl; if (null == stream) { continue; } if (stream.GetShortestDistanceFromLines(location) <= dist) { return(stream); } } } return(element); }