using System; using System.Drawing; using System.Windows.Forms; namespace Netron.Diagramming.Core { // ---------------------------------------------------------------------- /// /// Abstract base implementation of the /// interface. /// // ---------------------------------------------------------------------- public abstract class ControllerBase : IUndoSupport, IController { #region Events // ------------------------------------------------------------------ /// /// Occurs when the context menu is shown. /// // ------------------------------------------------------------------ public event EventHandler OnShowContextMenu; // ------------------------------------------------------------------ /// /// Occurs when a tool is asked to be deactivated. /// // ------------------------------------------------------------------ public event EventHandler OnToolDeactivate; // ------------------------------------------------------------------ /// /// Occurs when a tool is asked to be activated. /// // ------------------------------------------------------------------ public event EventHandler OnToolActivate; // ------------------------------------------------------------------ /// /// Occurs when the history has changed in the undo/redo mechanism. /// // ------------------------------------------------------------------ public event EventHandler OnHistoryChange; // ------------------------------------------------------------------ /// /// Occurs when the something got selected and the properties of it /// can/should be shown. /// // ------------------------------------------------------------------ public event EventHandler OnShowSelectionProperties; // ------------------------------------------------------------------ /// /// Occurs when an entity is added. /// This event usually is bubbled from one of the /// layers. /// // ------------------------------------------------------------------ public event EventHandler OnEntityAdded; // ------------------------------------------------------------------ /// /// Occurs when an entity is removed. /// This event usually is bubbled from one of the /// layers. /// // ------------------------------------------------------------------ public event EventHandler OnEntityRemoved; // ------------------------------------------------------------------ /// /// Occurs when the controller receives a mouse-down notification of /// the surface. This event is raised before the /// event is broadcasted down to the tools. /// // ------------------------------------------------------------------ public event EventHandler OnMouseDown; // ------------------------------------------------------------------ /// /// Occurs when the Ambience has changed. /// // ------------------------------------------------------------------ public event EventHandler OnAmbienceChanged; #endregion #region Tool Names public const string AlignBottomEdgesToolName = "Align Bottom Edges Tool"; public const string AlignCentersHorizToolName = "Align Centers Horizontally"; public const string AlignCentersVertToolName = "Align Centers Vertically"; public const string AlignLeftEdgesToolName = "Align Left Edges Tool"; public const string AlignRightEdgesToolName = "Align Right Edges Tool"; public const string AlignTopEdgesToolName = "Align Top Edges Tool"; public const string ComplexRectangleToolName = "ComplexRectangle Tool"; public const string ConnectionToolName = "Connection Tool"; public const string ConnectorMoverToolName = "Connector Mover Tool"; public const string ContextToolName = "Context Tool"; public const string CopyToolName = "Copy Tool"; public const string CutToolName = "Cut Tool"; public const string DeleteToolName = "Delete Tool"; public const string DragDropToolName = "DragDrop Tool"; public const string EllipseToolName = "Ellipse Tool"; public const string GroupToolName = "Group Tool"; public const string HitToolName = "Hit Tool"; public const string HoverToolName = "Hover Tool"; public const string ImageExportToolName = "Image Export Tool"; public const string MoveToolName = "Move Tool"; public const string MultiLineToolName = "MultiLine Tool"; public const string PanToolName = "Pan Tool"; public const string PasteToolName = "Paste Tool"; public const string PolygonToolName = "Polygon Tool"; public const string RectangleToolName = "Rectangle Tool"; public const string ScribbleToolName = "Scribble Tool"; public const string SelectionToolName = "Selection Tool"; public const string SendBackwardsToolName = "SendBackwards Tool"; public const string SendForwardsToolName = "SendForwards Tool"; public const string SendToBackToolName = "SendToBack Tool"; public const string SendToFrontToolName = "SendToFront Tool"; public const string TransformToolName = "Transform Tool"; public const string UngroupToolName = "Ungroup Tool"; public const string ZoomAreaToolName = "Zoom Area Tool"; public const string ZoomInToolName = "Zoom In Tool"; public const string ZoomOutToolName = "Zoom Out Tool"; #endregion #region Fields private bool eventsEnabled = true; private bool controllerEnabled = true; private IModel mModel; private UndoManager mUndoManager; ITool activeTool; /// /// the View field /// private IView mView; protected CollectionBase mouseListeners; protected CollectionBase keyboardListeners; protected CollectionBase dragdropListeners; protected IDiagramControl parentControl; protected CollectionBase registeredTools; protected CollectionBase registeredActivity; #endregion #region Properties /// /// Gets or sets a value indicating whether this is enabled. /// /// true if enabled; otherwise, false. public bool Enabled { get { return controllerEnabled; } set { controllerEnabled = value; } } // ------------------------------------------------------------------ /// /// Gets the currently active tool. This can be 'null'!!! /// // ------------------------------------------------------------------ public ITool ActiveTool { get { return this.activeTool; } } /// /// Gets or sets the parent control. /// /// The parent control. public IDiagramControl ParentControl { get { return parentControl; } internal set { parentControl = value; } } /// /// Gets the registered tools. /// /// The tools. public CollectionBase Tools { get { return registeredTools; } } /// /// Gets the undo manager. /// /// The undo manager. public UndoManager UndoManager { get { return mUndoManager; } } /// /// Gets or sets the model /// /// public IModel Model { get { return mModel; } set { AttachToModel(value); } } /// /// Gets or sets the view. /// /// The view. public IView View { get { return mView; } set { AttachToView(value); } } /// /// Attaches to the given view. /// /// The view. private void AttachToView(IView view) { if (view == null) throw new ArgumentNullException(); mView = view; } #endregion #region Constructor // ------------------------------------------------------------------ /// /// Default constructor. /// // ------------------------------------------------------------------ protected ControllerBase(IDiagramControl surface) { //doesn't work if you supply a null reference if (surface == null) { throw new NullReferenceException( "The diagram control assigned to the controller " + "cannot be 'null'"); } //create the undo/redo manager mUndoManager = new UndoManager(15); mUndoManager.OnHistoryChange += new EventHandler( mUndoManager_OnHistoryChange); #region Instantiation of listeners mouseListeners = new CollectionBase(); keyboardListeners = new CollectionBase(); dragdropListeners = new CollectionBase(); #endregion //keep a reference to the parent control parentControl = surface; AttachToSurface(parentControl); //Initialize the colorscheme ArtPalette.Init(); #region Tools: the registration order matters! /* The order in in which the tools are added matters, at least some of them. * The TransformTool should come before the HitTool and the MoveTool after the HitTool. * The order of the drawing tools does not matter. * It's also important to remark that the tools do not depend on the Model. */ registeredTools = new CollectionBase(); this.AddTool(new TransformTool(TransformToolName)); this.AddTool(new HitTool(HitToolName)); this.AddTool(new MoveTool(MoveToolName)); this.AddTool(new RectangleTool(RectangleToolName)); this.AddTool(new ComplexRectangleTool(ComplexRectangleToolName)); this.AddTool(new EllipseTool(EllipseToolName)); this.AddTool(new SelectionTool(SelectionToolName)); this.AddTool(new DragDropTool(DragDropToolName)); this.AddTool(new ConnectionTool(ConnectionToolName)); this.AddTool(new ConnectorMoverTool(ConnectorMoverToolName)); this.AddTool(new GroupTool(GroupToolName)); this.AddTool(new UngroupTool(UngroupToolName)); this.AddTool(new SendToBackTool(SendToBackToolName)); this.AddTool(new SendBackwardsTool(SendBackwardsToolName)); this.AddTool(new SendForwardsTool(SendForwardsToolName)); this.AddTool(new SendToFrontTool(SendToFrontToolName)); this.AddTool(new HoverTool(HoverToolName)); this.AddTool(new ContextTool(ContextToolName)); this.AddTool(new CopyTool(CopyToolName)); this.AddTool(new CutTool(CutToolName)); this.AddTool(new PasteTool(PasteToolName)); this.AddTool(new DeleteTool(DeleteToolName)); this.AddTool(new ScribbleTool(ScribbleToolName)); this.AddTool(new PolygonTool(PolygonToolName)); this.AddTool(new MultiLineTool(MultiLineToolName)); this.AddTool(new AlignBottomEdgesTool(AlignBottomEdgesToolName)); this.AddTool( new AlignCentersHorizontallyTool(AlignCentersHorizToolName)); this.AddTool( new AlignCentersVerticallyTool(AlignCentersVertToolName)); this.AddTool(new AlignLeftEdgesTool(AlignLeftEdgesToolName)); this.AddTool(new AlignRightEdgesTool(AlignRightEdgesToolName)); this.AddTool(new AlignTopEdgesTool(AlignTopEdgesToolName)); this.AddTool(new ZoomAreaTool(ZoomAreaToolName)); this.AddTool(new ZoomInTool(ZoomInToolName)); this.AddTool(new ZoomOutTool(ZoomOutToolName)); this.AddTool(new PanTool(PanToolName)); this.AddTool(new ImageExportTool(ImageExportToolName)); #endregion #region Hotkeys HotKeys keys = new HotKeys(this); this.keyboardListeners.Add(keys); #endregion #region Activities // This is in a way a waste of memory; the layouts should not // necessarily be loaded before they are actually requested. // You could register only the (string) names instead. // But for just a few algorithms this is OK and the advantage // of this registration is that one can register actions from // outside the library, in the hosting form for example. registeredActivity = new CollectionBase(); AddActivity(new RandomLayout(this)); AddActivity(new FruchtermanReingoldLayout(this)); AddActivity(new StandardTreeLayout(this)); AddActivity(new RadialTreeLayout(this)); AddActivity(new BalloonTreeLayout(this)); AddActivity(new ForceDirectedLayout(this)); #endregion } #endregion // ------------------------------------------------------------------ /// /// Attaches the given model to the controller. /// /// IModel // ------------------------------------------------------------------ protected virtual void AttachToModel(IModel model) { if (model == null) throw new ArgumentNullException(); mModel = model; mModel.OnEntityAdded += new EventHandler(mModel_OnEntityAdded); mModel.OnEntityRemoved += new EventHandler(mModel_OnEntityRemoved); mModel.OnAmbienceChanged += new EventHandler(mModel_OnAmbienceChanged); } // ------------------------------------------------------------------ /// /// Passes the OnAmbienceChanged event on. /// /// object /// AmbienceEventArgs // ------------------------------------------------------------------ void mModel_OnAmbienceChanged( object sender, AmbienceEventArgs e) { RaiseOnAmbienceChanged(e); } // ------------------------------------------------------------------ /// /// Passes the OnEntityRemoved event on. /// /// object /// EntityEventArgs // ------------------------------------------------------------------ void mModel_OnEntityRemoved( object sender, EntityEventArgs e) { RaiseOnEntityRemoved(e); } // ------------------------------------------------------------------ /// /// Passes the OnEntityAdded event on. /// /// object /// EntityEventArgs // ------------------------------------------------------------------ void mModel_OnEntityAdded( object sender, EntityEventArgs e) { RaiseOnEntityAdded(e); } // ------------------------------------------------------------------ /// /// Bubbles the OnHistoryChange event. /// /// The source of the event. /// The instance /// containing the event data. // ------------------------------------------------------------------ void mUndoManager_OnHistoryChange(object sender, EventArgs e) { RaiseOnHistoryChange(); } #region Methods // ------------------------------------------------------------------ /// /// Activates the text editor for the given text provider. /// /// ITextProvider /// bool: True if sucessful, false if not. // ------------------------------------------------------------------ public abstract bool ActivateTextEditor(ITextProvider textProvider); // ------------------------------------------------------------------ /// /// Changes the paint style of the selected entities. /// /// IPaintStyle // ------------------------------------------------------------------ public void ChangeStyle(IPaintStyle paintStyle) { // Note that you need a copy of the selected item otherwise the // undo/redo will fail once the selection has changed FillStyleCommand cmd = new FillStyleCommand( this, this.Model.Selection.SelectedItems.Copy(), paintStyle); this.UndoManager.AddUndoCommand(cmd); cmd.Redo(); } // ------------------------------------------------------------------ /// /// Changes the pen style of the selected entities. /// /// The pen style. // ------------------------------------------------------------------ public void ChangeStyle(IPenStyle penStyle) { PenStyleCommand cmd = new PenStyleCommand( this, this.Model.Selection.SelectedItems.Copy(), penStyle); this.UndoManager.AddUndoCommand(cmd); cmd.Redo(); } #region Event Raisers // ------------------------------------------------------------------ /// /// Raises the OnShowContextMenu event /// /// EntityMenuEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnShowContextMenu(EntityMenuEventArgs e) { EventHandler handler = OnShowContextMenu; if (handler != null) { handler(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnHistory change. /// // ------------------------------------------------------------------ public virtual void RaiseOnHistoryChange() { EventHandler handler = OnHistoryChange; if (handler != null) { handler(this, new HistoryChangeEventArgs( this.UndoManager.RedoText, this.UndoManager.UndoText)); } } // ------------------------------------------------------------------ /// /// Raises the event. /// /// ConnectionCollection event argument // ------------------------------------------------------------------ public virtual void RaiseOnToolDeactivate(ToolEventArgs e) { EventHandler handler = OnToolDeactivate; if (handler != null) { handler(this, e); } } // ------------------------------------------------------------------ /// /// Raises the event /// /// ConnectionCollection event argument // ------------------------------------------------------------------ public virtual void RaiseOnToolActivate(ToolEventArgs e) { EventHandler handler = OnToolActivate; if (handler != null) { handler(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnShowSelectionProperties event. /// /// The /// /// instance containing the event data. // ------------------------------------------------------------------ public virtual void RaiseOnShowSelectionProperties(SelectionEventArgs e) { EventHandler handler = OnShowSelectionProperties; if (handler != null) { handler(this, e); } } // ------------------------------------------------------------------ /// /// Raises the event. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ protected virtual void RaiseOnMouseDown(MouseEventArgs e) { if (OnMouseDown != null) OnMouseDown(this, e); } // ------------------------------------------------------------------ /// /// Raises the event. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ protected virtual void RaiseOnEntityAdded(EntityEventArgs e) { EventHandler handler = OnEntityAdded; if (handler != null) { handler(this, e); } } // ------------------------------------------------------------------ /// /// Raises the event. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ protected virtual void RaiseOnEntityRemoved(EntityEventArgs e) { EventHandler handler = OnEntityRemoved; if (handler != null) { handler(this, e); } } // ------------------------------------------------------------------ /// /// Raises the event. /// /// AmbienceEventArgs // ------------------------------------------------------------------ protected virtual void RaiseOnAmbienceChanged(AmbienceEventArgs e) { EventHandler handler = OnAmbienceChanged; if (handler != null) { handler(this, e); } } #endregion #region Tool (de)activation methods // ------------------------------------------------------------------ /// /// Deactivates the given tool. /// /// a registered ITool /// bool: True if successful. // ------------------------------------------------------------------ public bool DeactivateTool(ITool tool) { bool flag = false; if (tool != null && tool.Enabled && tool.IsActive) { //IEnumerator iEnumerator = tools.GetEnumerator(); //Tool tool2 = null; //while (iEnumerator.MoveNext()) //{ // tool2 = iEnumerator.Current is Tool; // if (tool2 != null && tool2 != tool) // { // tool2.ToolDeactivating(tool); // } //} flag = tool.DeactivateTool(); if (flag && eventsEnabled) { RaiseOnToolDeactivate(new ToolEventArgs(tool)); } } return flag; } // ------------------------------------------------------------------ /// /// Deactivates all tools. /// /// bool: True if successful. // ------------------------------------------------------------------ public bool DeactivateAllTools() { bool successful = true; // If the deactivation of any tool returns false, then we will // return false. foreach (ITool tool in this.Tools) { successful = successful & this.DeactivateTool(tool); } this.activeTool = null; return successful; } // ------------------------------------------------------------------ /// /// Activates the tool with the given name /// /// // ------------------------------------------------------------------ public void ActivateTool(string toolName) { if (!controllerEnabled) return; //using anonymous method here Predicate predicate = delegate(ITool tool) { if (tool.Name.ToLower() == toolName.ToLower())//not case sensitive return true; else return false; }; // First deactivate the current tool. if (this.activeTool != null) { this.activeTool.DeactivateTool(); } ITool foundTool = this.registeredTools.Find(predicate); ActivateTool(foundTool); } // ------------------------------------------------------------------ /// /// Suspends all tools /// // ------------------------------------------------------------------ public void SuspendAllTools() { foreach (ITool tool in this.Tools) { tool.IsSuspended = true; } } // ------------------------------------------------------------------ /// /// Unsuspends all tools. /// // ------------------------------------------------------------------ public void UnsuspendAllTools() { foreach (ITool tool in this.Tools) { tool.IsSuspended = false; } } // ------------------------------------------------------------------ /// /// Activates a registered tool /// /// a registered ITool /// bool: Returns if the activation was successful. True is /// returned if it was, false if not. // ------------------------------------------------------------------ private bool ActivateTool(ITool tool) { if (!controllerEnabled) return false; bool flag = false; if (tool != null && tool.CanActivate) { flag = tool.ActivateTool(); this.activeTool = tool; if (flag && eventsEnabled) { RaiseOnToolActivate(new ToolEventArgs(tool)); } } return flag; } #endregion // ------------------------------------------------------------------ /// /// Adds the given tool. /// /// The tool. // ------------------------------------------------------------------ public void AddTool(ITool tool) { tool.Controller = this; // Add the tool to the collection even if it doesn't attach to // anything (yet) registeredTools.Add(tool); IMouseListener mouseTool = null; if ((mouseTool = tool as IMouseListener) != null) mouseListeners.Add(mouseTool); IKeyboardListener keyboardTool = null; if ((keyboardTool = tool as IKeyboardListener) != null) keyboardListeners.Add(keyboardTool); IDragDropListener dragdropTool = null; if ((dragdropTool = tool as IDragDropListener) != null) dragdropListeners.Add(dragdropTool); // Watch when the tool is (de)activated so we can pass it on. tool.OnToolActivate += new EventHandler(AddedTool_OnToolActivate); tool.OnToolDeactivate += new EventHandler(AddedTool_OnToolDeactivate); } // ------------------------------------------------------------------ /// /// Called when an added tool is deactivated. The event is passed on /// by calling RaiseOnToolDeactivate. /// /// object /// ToolEventArgs // ------------------------------------------------------------------ protected void AddedTool_OnToolDeactivate(object sender, ToolEventArgs e) { ITool nextActiveToolInList = null; if (this.activeTool == e.Properties) { foreach (ITool tool in this.Tools) { if (tool.IsActive) { nextActiveToolInList = tool; break; } } activeTool = nextActiveToolInList; } this.RaiseOnToolDeactivate(e); } // ------------------------------------------------------------------ /// /// Called when an added tool is activated. The event is passed on /// by calling RaiseOnToolActivate. /// /// object /// ToolEventArgs // ------------------------------------------------------------------ protected void AddedTool_OnToolActivate(object sender, ToolEventArgs e) { this.RaiseOnToolActivate(e); } #region Activity // ------------------------------------------------------------------ /// /// Adds the given activity to the controller. /// /// The activity. // ------------------------------------------------------------------ public void AddActivity(IActivity activity) { registeredActivity.Add(activity); } // ------------------------------------------------------------------ /// /// Runs the given activity. /// /// The activity. // ------------------------------------------------------------------ protected void RunActivity(IActivity activity) { if (activity == null) return; PrepareActivity(activity); activity.Run(); } // ------------------------------------------------------------------ /// /// Runs the given activity. /// /// The activity. /// The milliseconds. // ------------------------------------------------------------------ protected void RunActivity(IActivity activity, int milliseconds) { if (activity == null) return; PrepareActivity(activity); activity.Run(milliseconds); } // ------------------------------------------------------------------ /// /// Prepares the activity. /// /// The activity. // ------------------------------------------------------------------ private void PrepareActivity(IActivity activity) { if (activity is IAction) (activity as IAction).Model = this.Model; if (activity is ILayout) { (activity as ILayout).Bounds = parentControl.ClientRectangle; (activity as ILayout).Center = new PointF(parentControl.ClientRectangle.Width / 2, parentControl.ClientRectangle.Height / 2); } } // ------------------------------------------------------------------ /// /// Runs the activity with the name specified. If no activity could /// by found with the given name then an exception is thrown. /// /// string: The name of the /// activity to run. // ------------------------------------------------------------------ public void RunActivity(string activityName) { if (!controllerEnabled) return; this.View.CurrentCursor = Cursors.WaitCursor; controllerEnabled = false; IActivity foundActivity = FindActivity(activityName); if (foundActivity != null) { RunActivity(foundActivity); } controllerEnabled = true; this.View.CurrentCursor = Cursors.Default; // After returning the canvas back to "normal", if the activity // wasn't found throw an exception (as specified by IController). if (foundActivity == null) { throw new Exception("Activity '" + activityName + "' could not be found."); } } // ------------------------------------------------------------------ /// /// Finds the activity with the given name. /// /// The name. /// IActivity // ------------------------------------------------------------------ protected IActivity FindActivity(string name) { //using anonymous method here Predicate predicate = delegate(IActivity activity) { if (activity.Name.ToLower() == name.ToLower())//not case sensitive return true; else return false; }; return this.registeredActivity.Find(predicate); } // ------------------------------------------------------------------ /// /// Runs the given activity for the specified time span. /// /// The name. /// The milliseconds. // ------------------------------------------------------------------ public void RunActivity(string name, int milliseconds) { if (!controllerEnabled) return; IActivity foundActivity = FindActivity(name); if (foundActivity != null) RunActivity(foundActivity, milliseconds); } #endregion // ------------------------------------------------------------------ /// /// Attaches this controller to the surface. /// /// The surface. // ------------------------------------------------------------------ protected virtual void AttachToSurface(IDiagramControl surface) { #region Mouse events surface.MouseDown += new MouseEventHandler(OnSurfaceMouseDown); surface.MouseUp += new MouseEventHandler(OnSurfaceMouseUp); surface.MouseMove += new MouseEventHandler(OnSurfaceMouseMove); surface.MouseHover += new EventHandler(OnSurfaceMouseHover); surface.MouseWheel += new MouseEventHandler(surface_MouseWheel); #endregion #region Keyboard events surface.KeyDown += new KeyEventHandler(surface_KeyDown); surface.KeyUp += new KeyEventHandler(surface_KeyUp); surface.KeyPress += new KeyPressEventHandler(surface_KeyPress); #endregion #region Dragdrop events surface.DragDrop += new DragEventHandler(surface_DragDrop); surface.DragEnter += new DragEventHandler(surface_DragEnter); surface.DragLeave += new EventHandler(surface_DragLeave); surface.DragOver += new DragEventHandler(surface_DragOver); surface.GiveFeedback += new GiveFeedbackEventHandler(surface_GiveFeedback); #endregion } // ------------------------------------------------------------------ /// /// Handles the MouseWheel event of the surface control. /// In the WinForm implementation this routine is not called /// because it gives some flickering effects; the hotkeys are /// implemented in the overriden OnMouseWheel method instead. /// /// The source of the event. /// The /// instance /// containing the event data. // ------------------------------------------------------------------ void surface_MouseWheel(object sender, MouseEventArgs e) { Point p = View.Origin; SizeF magnification = View.Magnification; int newValue = 0; if ((Control.ModifierKeys & Keys.Control) == Keys.Control) { #region Zooming SizeF s = magnification; // If zooming in, e.Delta is < 0 so a value of 1.1 is used to // offset the current magnification by. One mouse wheel // position on my PC corresponds to a delta of 120 (positive // for zooming out, neg for zooming in). float alpha = e.Delta > 0 ? 1.1F : 0.9F; View.Magnification = new SizeF( s.Width * alpha, s.Height * alpha); float w = (float)parentControl.AutoScrollPosition.X / (float)parentControl.AutoScrollMinSize.Width; float h = (float)parentControl.AutoScrollPosition.Y / (float)parentControl.AutoScrollMinSize.Height; // Resize the scrollbars proportionally to keep the actual // canvas constant. //s = new SizeF( // parentControl.AutoScrollMinSize.Width * alpha, // parentControl.AutoScrollMinSize.Height * alpha); //parentControl.AutoScrollMinSize = Size.Round(s); RectangleF pageBounds = Model.CurrentPage.Bounds; pageBounds.Inflate(s); SizeF deltaSize = new SizeF( pageBounds.Width - parentControl.ClientRectangle.Width, pageBounds.Height - parentControl.ClientRectangle.Height); if ((deltaSize.Width > 0) && (deltaSize.Height > 0)) { parentControl.AutoScrollMinSize = Size.Round(deltaSize); } //Point v = Origin; //v.Offset( // Convert.ToInt32((alpha - 1) * v.X), // Convert.ToInt32((alpha - 1) * v.Y)); //v.X = (int)Math.Round((double)(v.X - alpha)); //v.Y = (int)Math.Round((double)(v.Y - alpha)); //Origin = v; #endregion } else if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) { #region Pan horizontal newValue = p.X - Math.Sign(e.Delta) * 20; if (newValue > 0) View.Origin = new Point(newValue, p.Y); else View.Origin = new Point(0, p.Y); #endregion } else { #region Default vertical scroll newValue = View.Origin.Y - Math.Sign(e.Delta) * 20; if (newValue > 0) View.Origin = new Point( View.Origin.X, newValue); else View.Origin = new Point( View.Origin.X, 0); #endregion } this.parentControl.AutoScrollPosition = View.Origin; HandledMouseEventArgs eventargs = e as HandledMouseEventArgs; if (eventargs != null) eventargs.Handled = true; View.Invalidate(); } #region DragDrop event handlers /// /// Handles the GiveFeedback event of the surface control. /// /// The source of the event. /// The instance containing the event data. void surface_GiveFeedback(object sender, GiveFeedbackEventArgs e) { if (!controllerEnabled) { return; } foreach (IDragDropListener listener in dragdropListeners) { listener.GiveFeedback(e); } } /// /// Handles the DragOver event of the surface control. /// /// The source of the event. /// The instance containing the event data. void surface_DragOver(object sender, DragEventArgs e) { if (!controllerEnabled) { return; } foreach (IDragDropListener listener in dragdropListeners) { listener.OnDragOver(e); } } /// /// Handles the DragLeave event of the surface control. /// /// The source of the event. /// The instance containing the event data. void surface_DragLeave(object sender, EventArgs e) { if (!controllerEnabled) { return; } foreach (IDragDropListener listener in dragdropListeners) { listener.OnDragLeave(e); } } /// /// Handles the DragEnter event of the surface control. /// /// The source of the event. /// The instance containing the event data. void surface_DragEnter(object sender, DragEventArgs e) { if (!controllerEnabled) { return; } foreach (IDragDropListener listener in dragdropListeners) { listener.OnDragEnter(e); } } /// /// Handles the DragDrop event of the surface control. /// /// The source of the event. /// The instance containing the event data. void surface_DragDrop(object sender, DragEventArgs e) { if (!controllerEnabled) { return; } foreach (IDragDropListener listener in dragdropListeners) { listener.OnDragDrop(e); } } #endregion #region Keyboard event handlers void surface_KeyPress(object sender, KeyPressEventArgs e) { foreach (IKeyboardListener listener in keyboardListeners) { listener.KeyPress(e); } foreach (IDiagramEntity entity in this.Model.Selection.SelectedItems) { if (entity is IKeyboardListener) { (entity as IKeyboardListener).KeyPress(e); } } } void surface_KeyUp(object sender, KeyEventArgs e) { foreach (IKeyboardListener listener in keyboardListeners) { listener.KeyUp(e); } foreach (IDiagramEntity entity in this.Model.Selection.SelectedItems) { if (entity is IKeyboardListener) { (entity as IKeyboardListener).KeyUp(e); } } } void surface_KeyDown(object sender, KeyEventArgs e) { foreach (IKeyboardListener listener in keyboardListeners) { listener.KeyDown(e); } foreach (IDiagramEntity entity in this.Model.Selection.SelectedItems) { if (entity is IKeyboardListener) { (entity as IKeyboardListener).KeyDown(e); } } } #endregion #region Mouse event handlers /// /// Implements the observer pattern for the mouse hover event, /// communicating the event to all listeners implementing the /// necessary interface. /// /// The source of the event. /// The instance /// containing the event data. protected virtual void OnSurfaceMouseHover(object sender, EventArgs e) { //if (eventsEnabled) // RaiseOnMouseHover(e); //if (!controllerEnabled) // return; } /// /// Implements the observer pattern for the mouse down event, /// communicating the event to all listeners implementing the /// necessary interface. /// /// The source of the event. /// The /// instance /// containing the event data. protected virtual void OnSurfaceMouseDown( object sender, MouseEventArgs e) { #region Coordinates logic // Get a point adjusted by the current scroll position and zoom factor Point p = Point.Round( this.View.ViewToWorld(this.View.DeviceToView(e.Location))); HandledMouseEventArgs ce = new HandledMouseEventArgs( e.Button, e.Clicks, p.X, p.Y, e.Delta); #endregion if (eventsEnabled) RaiseOnMouseDown(ce); if (!controllerEnabled || ce.Handled) return; this.parentControl.Focus(); //(parentControl as Win.DiagramControl).toolTip.Show("Yihaaa", parentControl as Win.DiagramControl, ce.Location); //this selection process will work independently of the tools because //some tools need the current selection or hit entity //On the other hand, when drawing a simple rectangle for example the selection //should be off, so there is an overhead. //Selection.CollectEntitiesAt(e.Location); //raise the event to give the host the opportunity to show the properties of the selected item(s) //Note that if the selection is empty the property grid will show 'nothing'. RaiseOnShowSelectionProperties(new SelectionEventArgs(this.Model.Selection.SelectedItems.ToArray())); foreach (IMouseListener listener in mouseListeners) { if (listener.MouseDown(ce)) break; } } /// /// Handles the MouseMove event of the surface control. /// /// The source of the event. /// The /// instance /// containing the event data. protected virtual void OnSurfaceMouseMove(object sender, MouseEventArgs e) { if (!controllerEnabled) return; #region Coordinates logic // Get a point adjusted by the current scroll position and zoom // factor. //Point p = new Point(e.X - parentControl.AutoScrollPosition.X, e.Y - parentControl.AutoScrollPosition.Y); Point p = Point.Round(this.View.ViewToWorld( this.View.DeviceToView(e.Location))); MouseEventArgs ce = new MouseEventArgs( e.Button, e.Clicks, p.X, p.Y, e.Delta); #endregion foreach (IMouseListener listener in mouseListeners) { listener.MouseMove(ce); } } /// /// Handles the MouseUp event of the surface control. /// /// The source of the event. /// The instance containing the event data. protected virtual void OnSurfaceMouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { if (!controllerEnabled) return; #region Coordinates logic // Get a point adjusted by the current scroll position and zoom factor //Point p = new Point(e.X - parentControl.AutoScrollPosition.X, e.Y - parentControl.AutoScrollPosition.Y); Point p = Point.Round(this.View.ViewToWorld(this.View.DeviceToView(e.Location))); MouseEventArgs ce = new MouseEventArgs(e.Button, e.Clicks, p.X, p.Y, e.Delta); #endregion foreach (IMouseListener listener in mouseListeners) { listener.MouseUp(ce); } } #endregion // ------------------------------------------------------------------ /// /// Undo of the last action /// /// Calling this on a class level will call the Undo method /// of the last ICommand in the stack. // ------------------------------------------------------------------ public void Undo() { // Reset the tracker or show the tracker after the undo operation // since the undo does not take care of it this.View.ResetTracker(); mUndoManager.Undo(); this.View.ShowTracker(); this.View.Invalidate(); } // ------------------------------------------------------------------ /// /// Performs the actual action or redo in case the actions was undone /// before. /// /// Calling this on a class level will call the Redo method /// of the last ICommand in the stack. // ------------------------------------------------------------------ public void Redo() { mUndoManager.Redo(); this.View.ShowTracker(); } // ------------------------------------------------------------------ /// /// Selects all entities on the current page. The selection is /// cleared first. /// // ------------------------------------------------------------------ public void SelectAll() { this.View.ResetTracker(); this.Model.Selection.Clear(); this.Model.Selection.SelectedItems = this.Model.CurrentPage.Entities; this.View.ShowTracker(); this.View.Invalidate(); } // ------------------------------------------------------------------ /// /// Navigates to the next page. Nothing is performed if the last page /// is currently selected and 'wrap' is false. If 'wrap' is true, /// then the first page is selected. /// /// bool: Specifies if the collection is wrapped /// when the end is reached. // ------------------------------------------------------------------ public void GoForward(bool wrap) { // We can't go anywhere if there's only one page! if (Model.Pages.Count == 1) { return; } int index = Model.Pages.IndexOf(Model.CurrentPage); int newIndex = 0; // The index of the page to select. if (index >= (Model.Pages.Count - 1)) { // The last page is currently active, so if 'wrap' is // false then just return. if (wrap == false) { return; } // Otherwise, if 'wrap' is true then we want the first page // in the collection to be active. newIndex = 0; } else { newIndex = index + 1; } DeactivateAllTools(); View.HideTracker(); // Just in case there are selected items. Model.SetCurrentPage(Model.Pages[newIndex]); View.Invalidate(); } // ------------------------------------------------------------------ /// /// Navigates to the previous page. Nothing is performed if the first /// page is currently selected and 'wrap' is false. If 'wrap' is /// true, then the last page is selected if the current page is the /// first page. /// /// bool: Specifies if the collection is wrapped /// when the start is reached. // ------------------------------------------------------------------ public void GoBack(bool wrap) { // We can't go anywhere if there's only one page! if (Model.Pages.Count == 1) { return; } int index = Model.Pages.IndexOf(Model.CurrentPage); int newIndex = 0; // The index of the page to select. if (index == 0) { // The first page is currently active, so if 'wrap' is // false then just return. if (wrap == false) { return; } // Otherwise, since 'wrap' is true then we want the last page // in the collection to be active. newIndex = Model.Pages.Count - 1; } else { newIndex = index - 1; } DeactivateAllTools(); View.HideTracker(); // Just in case there are selected items. Model.SetCurrentPage(Model.Pages[newIndex]); View.Invalidate(); } #endregion } }