private void TreeViewImage_MouseClick(object sender, MouseEventArgs e) { string noArgumentsMessage = "[No arguments to display]"; Point mouseLocation = new Point(e.X, e.Y); NodeIcon selectedIcon = GetMatchingNodeIcon(mouseLocation); if (selectedIcon != null) { if (_currentToolTip != null) { _currentToolTip.Hide(treeViewImage); _currentToolTip.Dispose(); _currentToolTip = null; } string text = string.Empty; if (selectedIcon is TreeNodeIcon) { TreeNodeIcon treeIcon = selectedIcon as TreeNodeIcon; text = FormatText(treeIcon.Node.Arguments); if (string.IsNullOrEmpty(text)) { text = noArgumentsMessage; } text = treeIcon.Node.OperationName + Environment.NewLine + text; } else if (selectedIcon is MemoNodeIcon) { MemoNodeIcon memoIcon = selectedIcon as MemoNodeIcon; text = FormatText(memoIcon.Node.Arguments); if (string.IsNullOrEmpty(text)) { text = noArgumentsMessage; } text = memoIcon.Node.OperationName + Environment.NewLine + text; } text = text.Trim(); int numberOfLines = text.Count(c => c == '\r') + 1; _currentToolTip = new ToolTip(); _currentToolTip.IsBalloon = true; _currentToolTip.Show( text, treeViewImage, selectedIcon.Left + selectedIcon.Width - 25, selectedIcon.Top - 44 - 13 * numberOfLines); _toolTipMouseLocation = mouseLocation; _currentNodeIcon = selectedIcon; } }
public static Bitmap Render(SqlMemo memo, out List <MemoNodeIcon> memoNodeIcons) { if (memo == null) { throw new ArgumentNullException(nameof(memo)); } if (_font == null) { _font = new Font("Times New Roman", 10); } int columnCount; int rowCount; Dictionary <int, float> columnWidths; Dictionary <int, float> rowHeights; // Create a temporary bitmap so we can compute some size information Bitmap bitmap = new Bitmap(1, 1); using (Graphics graphics = Graphics.FromImage(bitmap)) { GetMemoExtent(memo, graphics, out columnCount, out rowCount, out columnWidths, out rowHeights); } int overallWidth = columnWidths.Sum(c => (int)Ceiling(c.Value)) + _headerColumnWidth + 1; int overallHeight = rowHeights.Sum(r => (int)Ceiling(r.Value)) + _headerRowHeight + 1; Rectangle[,] cells = new Rectangle[columnCount, rowCount]; bitmap = new Bitmap(overallWidth, overallHeight); using (Graphics graphics = Graphics.FromImage(bitmap)) { graphics.FillRectangle(Brushes.White, 0, 0, overallWidth, overallHeight); Pen gridlinePen = Pens.Black; graphics.DrawLine(gridlinePen, 0, 0, overallWidth, 0); // Draw the columns int columnPosition = _headerColumnWidth; for (int columnIndex = 0; columnIndex <= columnCount; columnIndex++) { graphics.DrawLine(gridlinePen, columnPosition, 0, columnPosition, overallHeight); if (columnIndex < columnCount) { int columnWidth = columnWidths.ContainsKey(columnIndex) ? (int)Ceiling(columnWidths[columnIndex]) : 0; columnPosition += columnWidth; } } graphics.DrawLine(gridlinePen, 0, 0, 0, overallHeight); // Draw the rows int rowPosition = _headerRowHeight; for (int rowIndex = 0; rowIndex <= rowCount; rowIndex++) { graphics.DrawLine(gridlinePen, 0, rowPosition, overallWidth, rowPosition); if (rowIndex < rowCount) { int rowHeight = rowHeights.ContainsKey(rowIndex) ? (int)Ceiling(rowHeights[rowIndex]) : 0; rowPosition += rowHeight; columnPosition = _headerColumnWidth; for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { int columnWidth = columnWidths.ContainsKey(columnIndex) ? (int)Ceiling(columnWidths[columnIndex]) : 0; columnPosition += columnWidth; cells[columnIndex, rowCount - 1 - rowIndex] = new Rectangle(columnPosition - columnWidth, rowPosition - rowHeight, columnWidth, rowHeight); } } } Brush operationNameBrush = Brushes.Black; Brush nodeIdentifierBrush = Brushes.Red; Brush headerBrush = Brushes.LightSkyBlue; Brush rootBrush = Brushes.LightGreen; // Draw the header row for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { string cellName = "x." + columnIndex.ToString(); SizeF size = graphics.MeasureString(cellName, _font); RectangleF containingRectangle = new RectangleF(cells[columnIndex, 0].Left + 1, 1, cells[columnIndex, 0].Width - 1, _headerRowHeight - 1); graphics.FillRectangle(headerBrush, containingRectangle); PointF stringStartingPoint = new PointF( containingRectangle.Left + containingRectangle.Width / 2 - size.Width / 2, containingRectangle.Top + containingRectangle.Height / 2 - size.Height / 2); graphics.DrawString(cellName, _font, nodeIdentifierBrush, stringStartingPoint); } // Draw the header column for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { string cellName = rowIndex.ToString() + ".x"; SizeF size = graphics.MeasureString(cellName, _font); RectangleF containingRectangle = new RectangleF(1, cells[0, rowIndex].Top + 1, _headerColumnWidth - 1, cells[0, rowIndex].Height - 1); graphics.FillRectangle(headerBrush, containingRectangle); PointF stringStartingPoint = new PointF( containingRectangle.Left + containingRectangle.Width / 2 - size.Width / 2, containingRectangle.Top + containingRectangle.Height / 2 - size.Height / 2); graphics.DrawString(cellName, _font, nodeIdentifierBrush, stringStartingPoint); } // Fill the upper left cell graphics.FillRectangle(headerBrush, 1, 1, _headerColumnWidth - 1, _headerRowHeight - 1); // Fill the root row. Should be only one, but we'll handle if that's not the case. foreach (SqlMemoGroup rootGroup in memo.Groups.Where(g => g.IsRoot)) { int rootRowIndex = rootGroup.GroupNumber; for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { Rectangle outerRectangle = cells[columnIndex, rootRowIndex]; Rectangle containingRectangle = new Rectangle(outerRectangle.Left + 1, outerRectangle.Top + 1, outerRectangle.Width - 1, outerRectangle.Height - 1); graphics.FillRectangle(rootBrush, containingRectangle); } } memoNodeIcons = new List <MemoNodeIcon>(); Dictionary <SqlMemoNodeIdentifier, MemoNodeIcon> nodeIndex = new Dictionary <SqlMemoNodeIdentifier, MemoNodeIcon>(); // Draw the nodes foreach (SqlMemoNode node in memo.Groups.SelectMany(g => g.Operations)) { int rowIndex = node.Identifier.GroupNumber; int columnIndex = node.Identifier.OperationNumber; SizeF fullSize = graphics.MeasureString(node.DisplayName, _font); SizeF operationSize = graphics.MeasureString(node.DisplayOperationName, _font); SizeF parentSize = graphics.MeasureString(node.DisplayParentName, _font); Rectangle outerRectangle = cells[columnIndex, rowIndex]; RectangleF containingRectangle = new RectangleF(outerRectangle.Left + 1, outerRectangle.Top + 1, outerRectangle.Width - 1, outerRectangle.Height - 1); PointF stringStartingPoint = new PointF( containingRectangle.Left + containingRectangle.Width / 2 - fullSize.Width / 2, containingRectangle.Top + containingRectangle.Height / 2 - fullSize.Height / 2); PointF parentStartingPoint = new PointF( stringStartingPoint.X + operationSize.Width, stringStartingPoint.Y); graphics.DrawString(node.DisplayOperationName, _font, operationNameBrush, stringStartingPoint); graphics.DrawString(node.DisplayParentName, _font, nodeIdentifierBrush, parentStartingPoint); MemoNodeIcon icon = new MemoNodeIcon(); icon.Node = node; icon.X = columnIndex; icon.Y = rowIndex; icon.Top = (int)containingRectangle.Top; icon.Left = (int)containingRectangle.Left; icon.Height = (int)containingRectangle.Height; icon.Width = (int)containingRectangle.Width; memoNodeIcons.Add(icon); if (nodeIndex.ContainsKey(node.Identifier) == false) { nodeIndex.Add(node.Identifier, icon); } } // Fixup parent links foreach (MemoNodeIcon icon in memoNodeIcons) { foreach (SqlMemoNode parentNode in icon.Node.Parents) { if (nodeIndex.ContainsKey(parentNode.Identifier)) { MemoNodeIcon parentIcon = nodeIndex[parentNode.Identifier]; icon.Parents.Add(parentIcon); } } } } return(bitmap); }