#region License Information /* HeuristicLab * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using HeuristicLab.Core.Networks; using HeuristicLab.Visualization; namespace HeuristicLab.Networks.Views.NetworkVisualization { public class NodeRectangle : Visualization.Rectangle, INetworkItemPrimitive { private readonly Dictionary port2PortRectangle = new Dictionary(); protected IGroup portRectangles; protected bool IgnoreVisualPropertiesChanges { get; set; } protected IVisualizableNode networkItem; public IVisualizableNode NetworkItem { get { return networkItem; } set { if (networkItem == value) return; if (networkItem != null) DeregisterNetworkItemEvents(); networkItem = value; if (networkItem != null) RegisterNetworkItemEvents(); UpdateToolTip(); LoadVisualProperties(); OnNetworkItemChanged(); } } public NodeRectangle(IChart chart, IVisualizableNode node) : base(chart, Point.Empty, Point.Empty) { NetworkItem = node; portRectangles = new Group(chart); foreach (var port in node.Ports) { var portRectangle = new PortRectangle(this, port); port2PortRectangle.Add(port, portRectangle); portRectangles.Add(portRectangle); } UpdatePortRectangles(); portRectangles.RedrawRequired += (sender, args) => OnRedrawRequired(); } protected virtual void RegisterNetworkItemEvents() { networkItem.NameChanged += NetworkItemNameChanged; if (networkItem.VisualProperties != null) { networkItem.VisualProperties.Changed += VisualProperties_Changed; } if (networkItem.Ports != null) { networkItem.Ports.ItemsAdded += Ports_ItemsAdded; networkItem.Ports.ItemsRemoved += Ports_ItemsRemoved; } } protected virtual void DeregisterNetworkItemEvents() { networkItem.NameChanged -= NetworkItemNameChanged; if (networkItem.VisualProperties != null) { networkItem.VisualProperties.Changed -= VisualProperties_Changed; } if (networkItem.Ports != null) { networkItem.Ports.ItemsAdded -= Ports_ItemsAdded; networkItem.Ports.ItemsRemoved -= Ports_ItemsRemoved; } } #region Overrides public override void SetPosition(PointD lowerLeft, PointD upperRight) { SuppressEvents = true; try { base.SetPosition(lowerLeft, upperRight); SaveVisualProperties(); UpdatePortRectangles(); } finally { SuppressEvents = false; OnRedrawRequired(); } } public override void Draw(Graphics graphics) { base.Draw(graphics); var p = Chart.TransformWorldToPixel(new PointD(LowerLeft.X, LowerLeft.Y + Size.Height)); using (var font = new Font(FontFamily.GenericSansSerif, (float)Math.Round(8.25 * Chart.WorldToPixelRatio.Width))) { graphics.DrawString(ToolTipText, font, Brushes.Black, p.X + 5, p.Y + 5); } portRectangles.Draw(graphics); } #endregion public PortRectangle GetPortRectangle(IPort name) { PortRectangle portRectangle; port2PortRectangle.TryGetValue(name, out portRectangle); return portRectangle; } #region Events public event EventHandler NetworkItemChanged; protected virtual void OnNetworkItemChanged() { var handler = NetworkItemChanged; if (handler != null) handler(this, EventArgs.Empty); } #endregion #region Event Handlers private void NetworkItemNameChanged(object sender, EventArgs e) { UpdateToolTip(); } private void VisualProperties_Changed(object sender, EventArgs e) { if (IgnoreVisualPropertiesChanges) return; LoadVisualProperties(); } private void Ports_ItemsAdded(object sender, Collections.CollectionItemsChangedEventArgs e) { foreach (var port in e.Items) { var portRectangle = new PortRectangle(this, port); port2PortRectangle.Add(port, portRectangle); portRectangles.Add(portRectangle); } SuppressEvents = true; try { UpdatePortRectangles(); } finally { SuppressEvents = false; OnRedrawRequired(); } } private void Ports_ItemsRemoved(object sender, Collections.CollectionItemsChangedEventArgs e) { foreach (var port in e.Items) { var portRectangle = port2PortRectangle[port]; port2PortRectangle.Remove(port); portRectangles.Remove(portRectangle); } UpdatePortRectangles(); OnRedrawRequired(); } #endregion #region Helpers private void UpdateToolTip() { ToolTipText = networkItem.Name; } private void LoadVisualProperties() { var offset = Chart.UpperRight - Chart.LowerLeft; var center = new PointD(Chart.LowerLeft.X + offset.DX * 0.5, Chart.LowerLeft.Y + offset.DY * 0.5); var size = Chart.TransformPixelToWorld(new Size(200, 100)); bool vpAvailable = networkItem != null && networkItem.VisualProperties != null; bool useDefaultLocation = !vpAvailable || double.IsNaN(networkItem.VisualProperties.X); bool useDefaultSize = !vpAvailable || double.IsNaN(networkItem.VisualProperties.Width); if (!useDefaultLocation) { center.X = networkItem.VisualProperties.X; center.Y = networkItem.VisualProperties.Y; } if (!useDefaultSize) { size.Width = networkItem.VisualProperties.Width; size.Height = networkItem.VisualProperties.Height; } var ll = new PointD(center.X - size.Width * 0.5, center.Y - size.Height * 0.5); var ur = ll + new Offset(size.Width, size.Height); SetPosition(ll, ur); } private void SaveVisualProperties() { if (networkItem == null) return; var visualProperties = networkItem.VisualProperties; var centerW = new PointD(LowerLeft.X + Size.Width * 0.5, UpperRight.Y - Size.Height * 0.5); IgnoreVisualPropertiesChanges = true; try { visualProperties.X = centerW.X; visualProperties.Y = centerW.Y; visualProperties.Width = Size.Width; visualProperties.Height = Size.Height; } finally { IgnoreVisualPropertiesChanges = false; } OnRedrawRequired(); } private void UpdatePortRectangles() { if (portRectangles == null) return; var rectangles = portRectangles.OfType().ToArray(); double space = Size.Width / (rectangles.Length + 1); for (int i = 0; i < rectangles.Length; i++) { double dx = Math.Round(space * (i + 1)); var point = LowerLeft + new Offset(dx, 0); rectangles[i].SetPosition(point); } } #endregion } }