internal void RegisterNodeType(Type type, string name, Image icon)
        {
            Contract.Requires(type != null);
            Contract.Requires(name != null);
            Contract.Requires(icon != null);

            var item = new TypeToolStripMenuItem
            {
                Image = icon,
                Text  = name,
                Value = type
            };

            item.Click += memoryTypeToolStripMenuItem_Click;

            changeTypeToolStripMenuItem.DropDownItems.Add(item);
        }
        public static IEnumerable <ToolStripItem> CreateToolStripMenuItems(Action <Type> handler, bool addNoneType)
        {
            Contract.Requires(handler != null);

            var clickHandler = new EventHandler((sender, e) => handler(((TypeToolStripMenuItem)sender).Value));

            var items = CreateToolStripItems(t =>
            {
                GetNodeInfoFromType(t, out var label, out var icon);

                var item = new TypeToolStripMenuItem
                {
                    Value = t,
                    Text  = label,
                    Image = icon
                };
                item.Click += clickHandler;
                return(item);
            }, p => new ToolStripMenuItem
            {
                Text  = p.GetType().ToString(),
                Image = p.Icon
            });

            if (addNoneType)
            {
                ToolStripItem noneItem = new TypeToolStripMenuItem
                {
                    Value = null,
                    Text  = "None"
                };

                items = items.Prepend(new ToolStripSeparator()).Prepend(noneItem);
            }

            return(items);
        }
        public static IEnumerable <ToolStripItem> CreateToolStripButtons(Action <Type> handler)
        {
            Contract.Requires(handler != null);

            var clickHandler = new EventHandler((sender, e) => handler((sender as TypeToolStripButton)?.Value ?? ((TypeToolStripMenuItem)sender).Value));

            return(CreateToolStripItems(t =>
            {
                GetNodeInfoFromType(t, out var label, out var icon);

                var item = new TypeToolStripButton
                {
                    Value = t,
                    ToolTipText = label,
                    DisplayStyle = ToolStripItemDisplayStyle.Image,
                    Image = icon
                };
                item.Click += clickHandler;
                return item;
            }, p => new ToolStripDropDownButton
            {
                ToolTipText = "",
                Image = p.Icon
            }, t =>
            {
                GetNodeInfoFromType(t, out var label, out var icon);

                var item = new TypeToolStripMenuItem
                {
                    Value = t,
                    Text = label,
                    Image = icon
                };
                item.Click += clickHandler;
                return item;
            }));
        }
        protected override void OnMouseClick(MouseEventArgs e)
        {
            editBox.Visible = false;

            foreach (var hotSpot in hotSpots)
            {
                if (hotSpot.Rect.Contains(e.Location))
                {
                    try
                    {
                        var hitObject = hotSpot.Node;

                        if (hotSpot.Type == HotSpotType.OpenClose)
                        {
                            hitObject.ToggleLevelOpen(hotSpot.Level);
                        }
                        else if (hotSpot.Type == HotSpotType.Click)
                        {
                            hitObject.Update(hotSpot);
                        }
                        else if (hotSpot.Type == HotSpotType.Select)
                        {
                            if (e.Button == MouseButtons.Left)
                            {
                                if (ModifierKeys == Keys.None)
                                {
                                    ClearSelection();

                                    hitObject.IsSelected = true;

                                    selectedNodes.Add(hotSpot);

                                    OnSelectionChanged();

                                    selectionAnchor = selectionCaret = hotSpot;
                                }
                                else if (ModifierKeys == Keys.Control)
                                {
                                    hitObject.IsSelected = !hitObject.IsSelected;

                                    if (hitObject.IsSelected)
                                    {
                                        selectedNodes.Add(hotSpot);
                                    }
                                    else
                                    {
                                        selectedNodes.Remove(selectedNodes.Where(c => c.Node == hitObject).FirstOrDefault());
                                    }

                                    OnSelectionChanged();
                                }
                                else if (ModifierKeys == Keys.Shift)
                                {
                                    if (selectedNodes.Count > 0)
                                    {
                                        var selectedNode = selectedNodes[0].Node;
                                        if (hitObject.ParentNode != null && selectedNode.ParentNode != hitObject.ParentNode)
                                        {
                                            continue;
                                        }

                                        var first = Utils.Min(selectedNodes[0], hotSpot, h => h.Node.Offset.ToInt32());
                                        var last  = first == hotSpot ? selectedNodes[0] : hotSpot;

                                        ClearSelection();

                                        var containerNode = selectedNode.ParentNode;
                                        foreach (var spot in containerNode.Nodes
                                                 .SkipWhile(n => n != first.Node)
                                                 .TakeUntil(n => n == last.Node)
                                                 .Select(n => new HotSpot {
                                            Address = containerNode.Offset.Add(n.Offset), Node = n
                                        }))
                                        {
                                            spot.Node.IsSelected = true;
                                            selectedNodes.Add(spot);
                                        }

                                        OnSelectionChanged();

                                        selectionAnchor = first;
                                        selectionCaret  = last;
                                    }
                                }
                            }
                            else if (e.Button == MouseButtons.Right)
                            {
                                // If there is only one selected node, select the node the user clicked at.
                                if (selectedNodes.Count <= 1)
                                {
                                    ClearSelection();

                                    hitObject.IsSelected = true;

                                    selectedNodes.Add(hotSpot);

                                    OnSelectionChanged();

                                    selectionAnchor = selectionCaret = hotSpot;
                                }

                                selectedNodeContextMenuStrip.Show(this, e.Location);
                            }
                        }
                        else if (hotSpot.Type == HotSpotType.Drop)
                        {
                            selectedNodeContextMenuStrip.Show(this, e.Location);
                        }
                        else if (hotSpot.Type == HotSpotType.Delete)
                        {
                            RemoveSelectedNodes();
                        }
                        else if (hotSpot.Type == HotSpotType.ChangeType)
                        {
                            var refNode = hitObject as BaseReferenceNode;
                            if (refNode != null)
                            {
                                EventHandler changeInnerType = (sender2, e2) =>
                                {
                                    var classNode = (sender2 as TypeToolStripMenuItem)?.Tag as ClassNode;
                                    if (classNode == null)
                                    {
                                        return;
                                    }

                                    if (IsCycleFree(refNode.ParentNode as ClassNode, classNode))
                                    {
                                        refNode.ChangeInnerNode(classNode);
                                    }
                                };

                                var menu = new ContextMenuStrip();
                                menu.Items.AddRange(
                                    project.Classes
                                    .OrderBy(c => c.Name)
                                    .Select(c =>
                                {
                                    var b = new TypeToolStripMenuItem
                                    {
                                        Text = c.Name,
                                        Tag  = c
                                    };
                                    b.Click += changeInnerType;
                                    return(b);
                                })
                                    .ToArray()
                                    );
                                menu.Show(this, e.Location);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Program.Logger.Log(ex);
                    }

                    Invalidate();
                }
            }

            base.OnMouseClick(e);
        }