/// <summary> /// Called when the tool is activated. /// </summary> protected override void OnActivateTool() { bool valid = true; //make sure we have the correct stuff on the table if (Selection.SelectedItems == null || Selection.SelectedItems.Count == 0) { MessageBox.Show("Nothing is selected, you need to select at least two items to create a group.", "Nothing selected.", MessageBoxButtons.OK, MessageBoxIcon.Hand); valid = false; } else if (Selection.SelectedItems.Count <= 1) { MessageBox.Show("You need at least two items to create a group.", "Multiple items.", MessageBoxButtons.OK, MessageBoxIcon.Hand); valid = false; } if (valid) { Bundle bundle = new Bundle(Selection.SelectedItems); GroupCommand cmd = new GroupCommand(this.Controller, bundle); this.Controller.UndoManager.AddUndoCommand(cmd); cmd.Redo(); } DeactivateTool(); return; }
// ------------------------------------------------------------------ /// <summary> /// Activates this tool - the View's current magnification is /// mulitiplied by 'ZoomFactor'. /// </summary> // ------------------------------------------------------------------ protected override void OnActivateTool() { base.OnActivateTool(); SizeF size = Controller.View.Magnification; SizeF autoScrollMinSize = Controller.ParentControl.AutoScrollMinSize; Point origin = Controller.View.Origin; Point parentAutoScrollPosition = Controller.ParentControl.AutoScrollPosition; Controller.View.Magnification = new SizeF( size.Width * myZoomFactor, size.Height * myZoomFactor); // Remember to also adjust the diagram's scroll bars. size = new SizeF( autoScrollMinSize.Width * myZoomFactor, autoScrollMinSize.Height * myZoomFactor); Controller.ParentControl.AutoScrollMinSize = Size.Round(size); // Should we set the Origin to the location of the selected items // if there are any? This will allow the user to zoom in on // a selection. if (this.Controller.Model.Selection.SelectedItems.Count > 0) { Bundle bundle = new Bundle(this.Controller.Model.Selection.SelectedItems); Point bundleLocation = bundle.Rectangle.Location; // Don't move the origin *exactly* to the bundle's location. // Offset it a little so the bundle is butted-up with the // upper-right hand corner of the screen. bundleLocation.Offset(-20, -20); origin.Offset(Point.Round(Controller.View.WorldToView( bundleLocation))); Controller.View.Origin = origin; } Controller.ParentControl.AutoScrollPosition = Controller.View.Origin; DeactivateTool(); }
/// <summary> /// When an entity is moved there are various possibilities: /// <list type="bullet"> /// <item> /// <term>a connector is moved</term> /// <description>in this case the moved connector can only be part of a onnection because moving shape-connectors is not allowed unless by means of the <see cref="ConnectorMoverTool"/>. /// If a connector attached to a connection is moved we have the following fork: /// <list type="bullet"> /// <item>the connector was attached</item> /// <description>the connector has a parent and needs to be detached before being moved and eventually attached to another connector</description> /// <item>the connector is moved</item> /// <description>this is a standard motion and is similar for any <see cref="IDiagramEntity"/> /// </description> /// <item>the connector ends up somewhere near another connector and will become attached to it</item> /// <description>the connector in the proximity of the moved connector will become the parent of it. Note that we previously detached any binding and that a connector can have only one parent.</description> /// </list> /// </description> /// </item> /// <item>an entity is moved</item> /// <description>the normal <see cref="MoveCommand"/> can be used</description> /// <item>a set of entities is moved</item> /// <description>we need to create a bundle to package the entities and then use the <see cref="MoveCommand"/></description> /// </list> /// Several important remarks are in order here: /// <list type="bullet"> /// <item>a connector can have only one parent</item> /// <item>we need to package a move action in a command but this command needs NOT to be performed (i.e. call the Redo() method) because the motion already occured through the MouseMove handler. Because of this situation we cannot perform a Redo() on the full package since it would move the entities twice. Hence, commands are execute just after their creation (except for the move). /// <item>when the stack of actions are undone the stack has to be reverted</item> /// </item> /// <item>whatever the situation is, the most economical way to code the different cases is by means of a <see cref="CompoundCommand"/> object</item> /// </list> /// </summary> /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param> public void MouseUp(MouseEventArgs e) { if(IsActive) { DeactivateTool(); //creation of the total undoredo package CompoundCommand package = new CompoundCommand(this.Controller); string message = string.Empty; //notice that the connector can only be a connection connector because of the MouseDown check above if(connectorMove) { #region We are moving a connection-connector #region Is the connector attached? //detach only if there is a parent different than a connection; the join of a chained connection is allowed to move if( Selection.Connector.AttachedTo != null && !typeof(IConnection).IsInstanceOfType(Selection.Connector.AttachedTo)) { DetachConnectorCommand detach = new DetachConnectorCommand(this.Controller, Selection.Connector.AttachedTo, Selection.Connector); detach.Redo(); package.Commands.Add(detach); } #endregion #region The moving part //a bundle might look like overkill here but it makes the coding model uniform Bundle bundle = new Bundle(Controller.Model); bundle.Entities.Add(Selection.Connector); MoveCommand move = new MoveCommand(this.Controller, bundle, new Point(lastPoint.X - initialPoint.X, lastPoint.Y - initialPoint.Y)); //no Redo() necessary here! package.Commands.Add(move); #endregion #region The re-attachment near another connector //let's see if the connection endpoints hit other connectors (different than the selected one!) //define a predicate delegate to filter things out otherwise the hit will return the moved connector which would results //in a stack overflow later on Predicate<IConnector> predicate = delegate(IConnector conn) { //whatever, except itself and any children of the moved connector //since this would entail a child becoming a parent! if(conn.Hit(e.Location) && conn != Selection.Connector && !Selection.Connector.AttachedConnectors.Contains(conn)) return true; return false; }; //find it! IConnector parentConnector = Selection.FindConnector(predicate); if(parentConnector != null) //aha, there's an attachment { BindConnectorsCommand binder = new BindConnectorsCommand(this.Controller, parentConnector, Selection.Connector); package.Commands.Add(binder); binder.Redo(); //this one is necessary since the redo cannot be performed on the whole compound command } #endregion message = "Connector move"; #endregion } else { #region We are moving entities other than a connector Bundle bundle = new Bundle(Controller.Model); bundle.Entities.AddRange(Selection.SelectedItems); MoveCommand cmd = new MoveCommand(this.Controller, bundle, new Point(lastPoint.X - initialPoint.X, lastPoint.Y - initialPoint.Y)); package.Commands.Add(cmd); //not necessary to perform the Redo action of the command since the mouse-move already moved the bundle! #endregion message = "Entities move"; } //reset the hovered connector, if any if (hoveredConnector != null) hoveredConnector.Hovered = false; package.Text = message; //whatever the content of the package we add it to the undo history this.Controller.UndoManager.AddUndoCommand(package); //show the tracker again this.Controller.View.ShowTracker(); } }
/// <summary> /// Handles the mouse up event /// </summary> /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param> public void MouseUp(MouseEventArgs e) { if (IsActive) { DeactivateTool(); if (fetchedConnector == null) return; Bundle bundle = new Bundle(Controller.Model); bundle.Entities.Add(fetchedConnector); MoveCommand cmd = new MoveCommand(this.Controller, bundle, new Point(lastPoint.X - initialPoint.X, lastPoint.Y - initialPoint.Y)); Controller.UndoManager.AddUndoCommand(cmd); //not necessary to perform the Redo action of the command since the mouse-move already moved the bundle! } }
// ------------------------------------------------------------------ /// <summary> /// Creates a Bitmap from the selected entities. If no entities are /// selected, then 'null' is returned. /// </summary> /// <returns>Bitmap</returns> // ------------------------------------------------------------------ public Bitmap ToBitmap() { if (SelectedItems.Count <= 0) { return null; } Graphics g = mController.View.Graphics; g.Transform = mController.View.ViewMatrix; g.SmoothingMode = SmoothingMode.HighQuality; Bundle bundle = new Bundle(SelectedItems.Copy()); return ImageExporter.FromBundle(bundle, g); }
// ------------------------------------------------------------------ /// <summary> /// Handles the actual rendering of the diagram to the print document. /// </summary> /// <param name="sender">object</param> /// <param name="e">PrintPageEventArgs</param> // ------------------------------------------------------------------ void PrintPage(object sender, PrintPageEventArgs e) { Graphics g = e.Graphics; IPage page = this.myDiagram.Controller.Model.Pages[currentPageIndex]; Bundle bundle = new Bundle(page.Entities); Matrix m = new Matrix(); m.Translate( -page.Bounds.Location.X, -page.Bounds.Location.Y); g.Transform = m; bundle.Paint(g); if ((currentPageIndex + 1) < this.numberOfPages) { currentPageIndex++; e.HasMorePages = true; } else { currentPageIndex = 0; e.HasMorePages = false; } }
// ------------------------------------------------------------------ /// <summary> /// Sets the magnification and origin of the diagram such that /// all entities in the current page are in view. /// </summary> // ------------------------------------------------------------------ public virtual void ZoomFit() { Bundle bundle = new Bundle(this.Model.CurrentPage.Entities); Rectangle bundleBounds = bundle.Rectangle; bundleBounds.Inflate(20, 20); bundleBounds.Offset(-10, -10); this.ZoomArea(bundleBounds); }