PageRenderTime 81ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/GraphLayout/Samples/xCodeMap/xGraphControl/VNodeX.cs

https://gitlab.com/hoseinyeganloo/automatic-graph-layout
C# | 336 lines | 270 code | 62 blank | 4 comment | 36 complexity | 15342f8b71259345185710eef96e82b0 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Media;
  8. using System.Windows.Media.Imaging;
  9. using System.Windows.Shapes;
  10. using Microsoft.Msagl.Core.Geometry.Curves;
  11. using Microsoft.Msagl.Core.Layout;
  12. using Microsoft.Msagl.Drawing;
  13. using Ellipse = Microsoft.Msagl.Core.Geometry.Curves.Ellipse;
  14. using LineSegment = Microsoft.Msagl.Core.Geometry.Curves.LineSegment;
  15. using Node = Microsoft.Msagl.Drawing.Node;
  16. using Point = Microsoft.Msagl.Core.Geometry.Point;
  17. using Rectangle = Microsoft.Msagl.Core.Geometry.Rectangle;
  18. using Shape = Microsoft.Msagl.Drawing.Shape;
  19. using Size = System.Windows.Size;
  20. namespace xCodeMap.xGraphControl
  21. {
  22. internal class XNode : IViewerNodeX, IInvalidatable {
  23. internal Path BoundaryPath;
  24. internal List<XEdge> inEdges = new List<XEdge>();
  25. internal List<XEdge> outEdges = new List<XEdge>();
  26. internal List<XEdge> selfEdges = new List<XEdge>();
  27. public LgNode LgNode { get; set; }
  28. private FrameworkElement _visualObject;
  29. public FrameworkElement VisualObject
  30. {
  31. get { return _visualObject; }
  32. }
  33. public Node Node { get; private set; }
  34. private string _category;
  35. public XNode(Node node, string category = null)
  36. {
  37. Node = node;
  38. _category = category;
  39. Border b = new Border();
  40. double size = node.Label.Text.Length * 9;
  41. b.Width = size + 12;
  42. b.Height = size * 2 / 3 + 4;
  43. _visualObject = b;
  44. Brush strokeBrush = CommonX.BrushFromMsaglColor(Node.Attr.Color);
  45. if (category != null)
  46. {
  47. Brush brush = Categories.GetBrush(_category);
  48. if (brush != null) strokeBrush = brush;
  49. }
  50. BoundaryPath = new Path {
  51. //Data = CreatePathFromNodeBoundary(),
  52. Stroke = strokeBrush,
  53. Fill = CommonX.BrushFromMsaglColor(Node.Attr.FillColor),
  54. StrokeThickness = Node.Attr.LineWidth
  55. };
  56. Node.Attr.LineWidthHasChanged += AttrLineWidthHasChanged;
  57. //Node.Attr.GeometryNode.LayoutChangeEvent += GeometryNodeBeforeLayoutChangeEvent;
  58. }
  59. double Scale() {
  60. return LgNode == null ? 1 : LgNode.Scale;
  61. }
  62. public void GeometryNodeBeforeLayoutChangeEvent(object sender, LayoutChangeEventArgs e) {
  63. var newBoundaryCurve = e.DataAfterChange as ICurve;
  64. if (newBoundaryCurve != null) {
  65. //just compare the bounding boxes for the time being
  66. var nb = newBoundaryCurve.BoundingBox;
  67. var box = Node.BoundingBox;
  68. if (Math.Abs(nb.Width - box.Width) > 0.00001 || Math.Abs(nb.Height - box.Height) > 0.00001)
  69. BoundaryCurveIsDirty = true;
  70. } else
  71. BoundaryCurveIsDirty = true;
  72. }
  73. void PositionPath(Rectangle box) {
  74. Canvas.SetLeft(BoundaryPath, box.Left + box.Width/2);
  75. Canvas.SetTop(BoundaryPath, box.Bottom + box.Height/2);
  76. }
  77. void AttrLineWidthHasChanged(object sender, EventArgs e) {
  78. BoundaryPath.StrokeThickness = Node.Attr.LineWidth;
  79. }
  80. Geometry DoubleCircle() {
  81. double w = Node.BoundingBox.Width;
  82. double h = Node.BoundingBox.Height;
  83. var pathGeometry = new PathGeometry();
  84. var r = new Rect(-w/2, -h/2, w, h);
  85. pathGeometry.AddGeometry(new EllipseGeometry(r));
  86. r.Inflate(-5, -5);
  87. pathGeometry.AddGeometry(new EllipseGeometry(r));
  88. return pathGeometry;
  89. }
  90. Geometry CreatePathFromNodeBoundary() {
  91. Geometry geometry;
  92. switch (Node.Attr.Shape) {
  93. case Shape.Box:
  94. case Shape.House:
  95. case Shape.InvHouse:
  96. case Shape.Diamond:
  97. case Shape.Octagon:
  98. geometry = CreateGeometryFromMsaglCurve(Node.Attr.GeometryNode.BoundaryCurve);
  99. break;
  100. case Shape.DoubleCircle:
  101. geometry = DoubleCircle();
  102. break;
  103. default:
  104. geometry = GetEllipseGeometry();
  105. break;
  106. }
  107. return geometry;
  108. }
  109. Geometry CreateGeometryFromMsaglCurve(ICurve iCurve) {
  110. var pathGeometry = new PathGeometry();
  111. var pathFigure = new PathFigure {IsClosed = true, IsFilled = true};
  112. Point c = Node.Attr.GeometryNode.Center;
  113. //we need to move the center to the origin, because the node position is later shifted to the center
  114. pathFigure.StartPoint = CommonX.WpfPoint(iCurve.Start - c);
  115. var curve = iCurve as Curve;
  116. if (curve != null) {
  117. AddCurve(pathFigure, c, curve);
  118. }
  119. else {
  120. var rect = iCurve as RoundedRect;
  121. if (rect != null)
  122. AddCurve(pathFigure, c, rect.Curve);
  123. else
  124. throw new Exception();
  125. }
  126. pathGeometry.Figures.Add(pathFigure);
  127. return pathGeometry;
  128. }
  129. static void AddCurve(PathFigure pathFigure, Point c, Curve curve) {
  130. foreach (ICurve seg in curve.Segments) {
  131. var ls = seg as LineSegment;
  132. if (ls != null)
  133. pathFigure.Segments.Add(new System.Windows.Media.LineSegment(CommonX.WpfPoint(ls.End - c), true));
  134. else {
  135. var ellipse = seg as Ellipse;
  136. pathFigure.Segments.Add(new ArcSegment(CommonX.WpfPoint(ellipse.End - c),
  137. new Size(ellipse.AxisA.Length, ellipse.AxisB.Length),
  138. Point.Angle(new Point(1, 0), ellipse.AxisA),
  139. ellipse.ParEnd - ellipse.ParEnd >= Math.PI,
  140. !ellipse.OrientedCounterclockwise()
  141. ? SweepDirection.Counterclockwise
  142. : SweepDirection.Clockwise, true));
  143. }
  144. }
  145. }
  146. Geometry GetEllipseGeometry() {
  147. return new EllipseGeometry(new System.Windows.Point(0, 0), Node.BoundingBox.Width/2,
  148. Node.BoundingBox.Height/2);
  149. }
  150. #region Implementation of IViewerObject
  151. public DrawingObject DrawingObject {
  152. get { return Node; }
  153. }
  154. public bool MarkedForDragging { get; set; }
  155. public event EventHandler MarkedForDraggingEvent;
  156. public event EventHandler UnmarkedForDraggingEvent;
  157. #endregion
  158. public IEnumerable<IViewerEdge> InEdges {
  159. get { return inEdges; }
  160. }
  161. public IEnumerable<IViewerEdge> OutEdges {
  162. get { return outEdges; }
  163. }
  164. public IEnumerable<IViewerEdge> SelfEdges {
  165. get { return selfEdges; }
  166. }
  167. public void SetStrokeFill() {
  168. throw new NotImplementedException();
  169. }
  170. public void AddPort(Port port) {
  171. }
  172. public void RemovePort(Port port) {
  173. }
  174. private TextBlock _vTitle;
  175. private Image _vIcon;
  176. public void Invalidate(double scale = 1)
  177. {
  178. if (BoundaryCurveIsDirty) {
  179. BoundaryPath.Data = CreatePathFromNodeBoundary();
  180. BoundaryCurveIsDirty = false;
  181. }
  182. PositionPath(Node.BoundingBox);
  183. var node_scale = Scale();
  184. if (_visualObject != null) {
  185. if (node_scale < 0.5)
  186. {
  187. if (_visualObject.Visibility != Visibility.Hidden)
  188. {
  189. _visualObject.Visibility = Visibility.Hidden;
  190. BoundaryPath.Fill = BoundaryPath.Stroke;
  191. }
  192. }
  193. else
  194. {
  195. if (_visualObject.Visibility != Visibility.Visible)
  196. {
  197. _visualObject.Visibility = Visibility.Visible;
  198. BoundaryPath.Fill = CommonX.BrushFromMsaglColor(Node.Attr.FillColor);
  199. }
  200. if (_vTitle == null)
  201. {
  202. Grid g = new Grid();
  203. ((Border)_visualObject).Child = g;
  204. g.Margin = new Thickness(4);
  205. g.VerticalAlignment = VerticalAlignment.Center;
  206. g.HorizontalAlignment = HorizontalAlignment.Center;
  207. g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
  208. g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  209. _vTitle = new TextBlock { Text = Node.Label.Text, Name = "Title" };
  210. _vTitle.VerticalAlignment = VerticalAlignment.Center;
  211. g.Children.Add(_vTitle);
  212. Grid.SetColumn(_vTitle, 1);
  213. if (_category != null)
  214. {
  215. ImageSource src = Categories.GetIcon(_category);
  216. if (src != null) {
  217. _vIcon = new Image { Source = src };
  218. _vIcon.VerticalAlignment = VerticalAlignment.Center;
  219. RenderOptions.SetBitmapScalingMode(_vIcon, BitmapScalingMode.HighQuality);
  220. g.Children.Add(_vIcon);
  221. }
  222. }
  223. }
  224. double fontSize = Math.Min(12 / (node_scale * scale), 12);
  225. _vTitle.FontSize = fontSize;
  226. if (_vIcon != null) _vIcon.Width = fontSize * 2;
  227. CommonX.PositionElement(_visualObject, Node.BoundingBox.Center, node_scale);
  228. }
  229. }
  230. }
  231. public override string ToString() {
  232. return Node.Id;
  233. }
  234. protected bool BoundaryCurveIsDirty { get; set; }
  235. internal double BorderPathThickness
  236. {
  237. set
  238. {
  239. BoundaryPath.StrokeThickness = value;
  240. }
  241. }
  242. }
  243. internal static class Categories
  244. {
  245. internal static Brush GetBrush(string category)
  246. {
  247. switch (category)
  248. {
  249. case "Class": return Brushes.DarkRed;
  250. case "Method": return Brushes.MediumVioletRed;
  251. case "Property": return Brushes.DimGray;
  252. case "Field": return Brushes.MidnightBlue;
  253. default: return null;
  254. }
  255. }
  256. internal static ImageSource GetIcon(string category)
  257. {
  258. switch (category)
  259. {
  260. case "Class":
  261. case "Method":
  262. case "Property":
  263. case "Field":
  264. case "Interface":
  265. case "Namespace":
  266. case "Delegate":
  267. case "Event":
  268. case "Solution":
  269. return new BitmapImage(new Uri("Images/Icon_" + category + ".png", UriKind.RelativeOrAbsolute));
  270. default: return null;
  271. }
  272. }
  273. }
  274. }