using System; using System.Diagnostics; using System.Collections; using System.Drawing; using System.Windows.Forms; namespace Netron.Diagramming.Core { class ConnectionTool : AbstractTool, IMouseListener { #region Fields /// /// the location of the mouse when the motion starts /// private Point initialPoint; private bool doDraw; #endregion #region Constructor /// /// Initializes a new instance of the class. /// /// The name of the tool. public ConnectionTool(string name) : base(name) { } #endregion #region Methods /// /// Called when the tool is activated. /// protected override void OnActivateTool() { Controller.View.CurrentCursor = CursorPalette.Grip; this.SuspendOtherTools(); doDraw = false; } /// /// Handles the mouse down event /// /// The instance containing the event data. /// Returns 'true' if the event was handled, otherwise 'false'. public bool MouseDown(MouseEventArgs e) { if (e == null) throw new ArgumentNullException("The argument object is 'null'"); if (e.Button == MouseButtons.Left && Enabled && !IsSuspended) { initialPoint = e.Location; doDraw = true; return true; } return false; } /// /// Handles the mouse move event /// /// The instance containing the event data. public void MouseMove(MouseEventArgs e) { if (e == null) throw new ArgumentNullException("The argument object is 'null'"); Point point = e.Location; if (IsActive) { if (foundConnector != null) foundConnector.Hovered = false; foundConnector = this.Controller.Model.Selection.FindConnectorAt(e.Location); if (foundConnector != null) foundConnector.Hovered = true; } if (IsActive && doDraw) { Controller.View.PaintGhostLine(initialPoint, point); Controller.View.Invalidate(System.Drawing.Rectangle.Inflate(Controller.View.Ghost.Rectangle, 20, 20)); } } private IConnector foundConnector; /// /// /// /// The instance containing the event data. public void MouseUp(MouseEventArgs e) { if (IsActive) { // First, make sure the initial point is far enough away from // the final point to make a connection. int maxX = Math.Abs(Math.Max(initialPoint.X, e.Location.X)); int maxY = Math.Abs(Math.Max(initialPoint.Y, e.Location.Y)); if (!(maxX > ConnectionBase.MinLength) || !(maxY > ConnectionBase.MinLength)) { return; } //whatever comes hereafter, a compund command is the most economic approach CompoundCommand package = new CompoundCommand(this.Controller); //let's see if the connection endpoints hit other connectors //note that the following can be done because the actual connection has not been created yet //otherwise the search would find the endpoints of the newly created connection, which //would create a loop and a stack overflow! IConnector startConnector = this.Controller.Model.Selection.FindConnectorAt(initialPoint); IConnector endConnector = this.Controller.Model.Selection.FindConnectorAt(e.Location); #region Create the new connection Connection cn = new Connection(this.initialPoint, e.Location, this.Controller.Model); AddConnectionCommand newcon = new AddConnectionCommand(this.Controller, cn); #endregion #region Initial attachment? if (startConnector != null) { BindConnectorsCommand bindStart = new BindConnectorsCommand(this.Controller, startConnector, cn.From); package.Commands.Add(bindStart); } #endregion #region Final attachment? if (endConnector != null) { BindConnectorsCommand bindEnd = new BindConnectorsCommand(this.Controller, endConnector, cn.To); package.Commands.Add(bindEnd); } #endregion package.Text = "New connection"; package.Commands.Add(newcon); this.Controller.UndoManager.AddUndoCommand(package); //do it all package.Redo(); //reset highlight of the found connector if (foundConnector != null) foundConnector.Hovered = false; //drop the painted ghost Controller.View.ResetGhost(); this.doDraw = false; } } #endregion } }