private bool PrepareConnection(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo, Action action) { // if we're not dealing with filter shapes... well, what the f**k?! get out of here! FilterSetupShapeBase shape = shapeAtCursorInfo.Shape as FilterSetupShapeBase; if (shape == null) throw new Exception("Can't connect a shape that isn't a FilterSetup shape!"); if (shape.OutputCount <= 0) return false; // get the starting control point for the line; ie. the first unused output for the shape, or the selected control point (if the mouse is over an output) ControlPointId connectionPoint = ControlPointId.None; if (shapeAtCursorInfo.IsCursorAtConnectionPoint && shape.GetTypeForControlPoint(shapeAtCursorInfo.ControlPointId) == FilterSetupShapeBase.FilterShapeControlPointType.Output) { connectionPoint = shapeAtCursorInfo.ControlPointId; } else { // try and find the first unconnected output if the mouse isn't over a specific control point for (int i = 0; i < shape.OutputCount; i++) { ControlPointId currentPoint = shape.GetControlPointIdForOutput(i); if (shape.GetConnectionInfos(currentPoint, null).Count() == 0) { connectionPoint = currentPoint; break; } } // if we couldn't find an unconnected point, just default to the first if (connectionPoint == ControlPointId.None) { connectionPoint = shape.GetControlPointIdForOutput(0); } } DataFlowConnectionLine line = (DataFlowConnectionLine) diagramPresenter.Project.ShapeTypes["DataFlowConnectionLine"].CreateInstance(); diagramPresenter.InsertShape(line); diagramPresenter.Diagram.Shapes.SetZOrder(line, 100); line.SecurityDomainName = ConfigFiltersAndPatching.SECURITY_DOMAIN_MOVABLE_SHAPE_WITH_CONNECTIONS; line.EndCapStyle = diagramPresenter.Project.Design.CapStyles.ClosedArrow; line.SourceDataFlowComponentReference = new DataFlowComponentReference(shape.DataFlowComponent, shape.GetOutputNumberForControlPoint( connectionPoint)); line.DestinationDataComponent = null; line.Connect(ControlPointId.FirstVertex, shape, connectionPoint); line.Disconnect(ControlPointId.LastVertex); line.MoveControlPointTo(ControlPointId.LastVertex, mouseState.X, mouseState.Y, ResizeModifiers.None); currentConnectionLine = line; StartToolAction(diagramPresenter, (int) action, ActionStartMouseState, true); return true; }
/// <summary> /// Decide which tool action is suitable for the current mouse state. /// </summary> private Action DetermineMouseMoveAction(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { switch (CurrentAction) { case Action.None: case Action.MoveHandle: case Action.MoveShape: case Action.SelectWithFrame: case Action.ConnectShapes: // Do not change the current action return CurrentAction; case Action.Select: if (mouseState.IsButtonDown(MouseButtonsDg.Left)) { // if we're doing something with the left mouse button, it will be a 'drag' style action if (!IsDragActionFeasible(mouseState)) { return CurrentAction; } // Check if cursor is over a control point and moving grips is feasible if (selectedShapeAtCursorInfo.IsCursorAtGrip) { if (IsMoveHandleFeasible(diagramPresenter, mouseState, selectedShapeAtCursorInfo)) return Action.MoveHandle; else return Action.SelectWithFrame; } else { // If there is no shape under the cursor, start a SelectWithFrame action, // otherwise start a MoveShape action bool canMove = false; if (!selectedShapeAtCursorInfo.IsEmpty) { // If there are selected shapes, check these shapes... canMove = IsMoveShapeFeasible(diagramPresenter, mouseState, selectedShapeAtCursorInfo); } else { // ... otherwise check the shape under the cursor as it will be selected // before starting a move action canMove = IsMoveShapeFeasible(diagramPresenter, mouseState, shapeAtCursorInfo); } return canMove ? Action.MoveShape : Action.SelectWithFrame; } } else if (mouseState.IsButtonDown(MouseButtonsDg.Right)) { if (IsConnectFromShapeFeasible(diagramPresenter, mouseState, shapeAtCursorInfo)) { return Action.ConnectShapes; } } return CurrentAction; default: throw new NShapeUnsupportedValueException(CurrentAction); } }
// (Un)Select shape unter the mouse pointer private bool PerformSelection(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { bool result = false; bool multiSelect = mouseState.IsKeyPressed(KeysDg.Control) || mouseState.IsKeyPressed(KeysDg.Shift); // When selecting shapes conteolpoints should be ignored as the user does not see them // until a shape is selected const ControlPointCapabilities capabilities = ControlPointCapabilities.None; const int range = 0; // Determine the shape that has to be selected: Shape shapeToSelect = null; if (!selectedShapeAtCursorInfo.IsEmpty) { // When in multiSelection mode, unselect the selected shape under the cursor if (multiSelect) shapeToSelect = selectedShapeAtCursorInfo.Shape; else { // First, check if the selected shape under the cursor has children that can be selected shapeToSelect = selectedShapeAtCursorInfo.Shape.Children.FindShape(mouseState.X, mouseState.Y, capabilities, range, null); // Second, check if the selected shape under the cursor has siblings that can be selected if (shapeToSelect == null && selectedShapeAtCursorInfo.Shape.Parent != null) { shapeToSelect = selectedShapeAtCursorInfo.Shape.Parent.Children.FindShape(mouseState.X, mouseState.Y, capabilities, range, selectedShapeAtCursorInfo.Shape); // Discard found shape if it is the selected shape at cursor if (shapeToSelect == selectedShapeAtCursorInfo.Shape) shapeToSelect = null; if (shapeToSelect == null) { foreach ( Shape shape in selectedShapeAtCursorInfo.Shape.Parent.Children.FindShapes(mouseState.X, mouseState.Y, capabilities, range)) { if (shape == selectedShapeAtCursorInfo.Shape) continue; // Ignore layer visibility for child shapes shapeToSelect = shape; break; } } } } } // If there was a shape to select related to the selected shape under the cursor // (a child or a sibling of the selected shape or a shape below it), // try to select the first non-selected shape under the cursor if (shapeToSelect == null && shapeAtCursorInfo.Shape != null && shapeAtCursorInfo.Shape.ContainsPoint(mouseState.X, mouseState.Y)) shapeToSelect = shapeAtCursorInfo.Shape; // If a new shape to select was found, perform selection if (shapeToSelect != null) { // (check if multiselection mode is enabled (Shift + Click or Ctrl + Click)) if (multiSelect) { // if multiSelect is enabled, add/remove to/from selected selectedShapes... if (diagramPresenter.SelectedShapes.Contains(shapeToSelect)) { // if object is selected -> remove from selection diagramPresenter.UnselectShape(shapeToSelect); RemovePreviewOf(shapeToSelect); result = true; } else { // If object is not selected -> add to selection diagramPresenter.SelectShape(shapeToSelect, true); result = true; } } else { // ... otherwise deselect all selectedShapes but the clicked object ClearPreviews(); // check if the clicked shape is a child of an already selected shape Shape childShape = null; if (diagramPresenter.SelectedShapes.Count == 1 && diagramPresenter.SelectedShapes.TopMost.Children != null && diagramPresenter.SelectedShapes.TopMost.Children.Count > 0) { childShape = diagramPresenter.SelectedShapes.TopMost.Children.FindShape(mouseState.X, mouseState.Y, ControlPointCapabilities.None, 0, null); } diagramPresenter.SelectShape(childShape ?? shapeToSelect, false); result = true; } // validate if the desired shape or its parent was selected if (shapeToSelect.Parent != null) { if (!diagramPresenter.SelectedShapes.Contains(shapeToSelect)) if (diagramPresenter.SelectedShapes.Contains(shapeToSelect.Parent)) shapeToSelect = shapeToSelect.Parent; } } else if (selectedShapeAtCursorInfo.IsEmpty) { // if there was no other shape to select and none of the selected shapes is under the cursor, // clear selection if (!multiSelect) { if (diagramPresenter.SelectedShapes.Count > 0) { diagramPresenter.UnselectAll(); ClearPreviews(); result = true; } } } return result; }
private bool IsConnectFromShapeFeasible(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { if (shapeAtCursorInfo.IsEmpty || mouseState.IsEmpty) return false; if (!diagramPresenter.Project.SecurityManager.IsGranted(Permission.Connect, shapeAtCursorInfo.Shape)) return false; if (shapeAtCursorInfo.Shape is FilterSetupShapeBase) { FilterSetupShapeBase filterShape = shapeAtCursorInfo.Shape as FilterSetupShapeBase; // only check OUTPUT count; we want to enforce the 'drag from OUTPUT, to INPUT' paradigm if (filterShape.OutputCount > 0) return true; } return false; }
private bool IsMoveHandleFeasible(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { if (shapeAtCursorInfo.IsEmpty) return false; // Collides with the resize modifiers //if (mouseState.IsKeyPressed(KeysDg.Shift)) return false; if (shapeAtCursorInfo.Shape.HasControlPointCapability(shapeAtCursorInfo.ControlPointId, ControlPointCapabilities.Glue)) { if (!diagramPresenter.Project.SecurityManager.IsGranted(Permission.Connect, diagramPresenter.SelectedShapes)) return false; } else { if (!diagramPresenter.Project.SecurityManager.IsGranted(Permission.Layout, diagramPresenter.SelectedShapes)) return false; } if ( !shapeAtCursorInfo.Shape.HasControlPointCapability(shapeAtCursorInfo.ControlPointId, ControlPointCapabilities.Resize | ControlPointCapabilities.Glue /*| ControlPointCapabilities.Movable*/)) return false; if (diagramPresenter.SelectedShapes.Count > 1) { // GluePoints may only be moved alone if (shapeAtCursorInfo.Shape.HasControlPointCapability(shapeAtCursorInfo.ControlPointId, ControlPointCapabilities.Glue)) return false; // Check if all shapes that are going to be resizes are of the same type Shape lastShape = null; foreach (Shape shape in diagramPresenter.SelectedShapes) { if (lastShape != null && lastShape.Type != shape.Type) return false; lastShape = shape; } } return true; }
private bool IsMoveShapeFeasible(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { if (shapeAtCursorInfo.IsEmpty || mouseState.IsEmpty) return false; if (!diagramPresenter.Project.SecurityManager.IsGranted(Permission.Layout, shapeAtCursorInfo.Shape)) return false; if (diagramPresenter.SelectedShapes.Count > 0 && !diagramPresenter.Project.SecurityManager.IsGranted(Permission.Layout, diagramPresenter.SelectedShapes)) return false; if (!shapeAtCursorInfo.Shape.ContainsPoint(mouseState.X, mouseState.Y)) return false; if (shapeAtCursorInfo.Shape.HasControlPointCapability(ControlPointId.Reference, ControlPointCapabilities.Glue)) if (shapeAtCursorInfo.Shape.IsConnected(ControlPointId.Reference, null) != ControlPointId.None) return false; // Check if the shape is connected to other shapes with its glue points if (diagramPresenter.SelectedShapes.Count == 0) { // Check if the non-selected shape at cursor (which will be selected) owns glue points connected to other shapes foreach (ControlPointId id in shapeAtCursorInfo.Shape.GetControlPointIds(ControlPointCapabilities.Glue)) if (shapeAtCursorInfo.Shape.IsConnected(id, null) != ControlPointId.None) return false; } else if (diagramPresenter.SelectedShapes.Contains(shapeAtCursorInfo.Shape)) { // ToDo: If there are *many* shapes selected (e.g. 10000), this check will be extremly slow... if (diagramPresenter.SelectedShapes.Count < 10000) { // LinearShapes that own connected gluePoints may not be moved. foreach (Shape shape in diagramPresenter.SelectedShapes) { if (shape is ILinearShape) { foreach (ControlPointId gluePointId in shape.GetControlPointIds(ControlPointCapabilities.Glue)) { ShapeConnectionInfo sci = shape.GetConnectionInfo(gluePointId, null); if (!sci.IsEmpty) { // Allow movement if the connected shapes are moved together if (!diagramPresenter.SelectedShapes.Contains(sci.OtherShape)) return false; } } } } } } return true; }
/// <summary> /// Creates a new preview line shape /// </summary> private void ExtendLine(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo targetShapeInfo) { // Try to find a connection target if (!targetShapeInfo.IsEmpty && targetShapeInfo.ControlPointId != ControlPointId.None) { // Start ToolAction StartToolAction(diagramPresenter, (int)Action.ExtendLine, mouseState, true); modifiedLinearShape = (ILinearShape)targetShapeInfo.Shape; // create new preview shape CreatePreview(diagramPresenter); PreviewShape.CopyFrom(targetShapeInfo.Shape); // Template will be copied but this is not really necessary as all styles will be overwritten with preview styles PreviewShape.MakePreview(diagramPresenter.Project.Design); pointAtCursor = targetShapeInfo.ControlPointId; Point pointPos = targetShapeInfo.Shape.GetControlPointPosition(pointAtCursor); if (pointAtCursor == ControlPointId.FirstVertex) { ControlPointId insertId = PreviewLinearShape.GetNextVertexId(pointAtCursor); lastInsertedPointId = PreviewLinearShape.InsertVertex(insertId, pointPos.X, pointPos.Y); } else lastInsertedPointId = PreviewLinearShape.InsertVertex(pointAtCursor, pointPos.X, pointPos.Y); ResizeModifiers resizeModifier = GetResizeModifier(mouseState); PreviewShape.MoveControlPointTo(pointAtCursor, mouseState.X, mouseState.Y, resizeModifier); } }
private bool IsEditCaptionFeasible(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { if (shapeAtCursorInfo.IsEmpty || mouseState.IsEmpty) return false; if (!diagramPresenter.Project.SecurityManager.IsGranted(Permission.ModifyData, shapeAtCursorInfo.Shape)) return false; if (!shapeAtCursorInfo.IsCursorAtCaption) return false; if (mouseState.IsKeyPressed(KeysDg.Control) || mouseState.IsKeyPressed(KeysDg.Shift)) return false; return true; }
private bool IsRotatatingFeasible(IDiagramPresenter diagramPresenter, ShapeAtCursorInfo shapeAtCursorInfo) { if (shapeAtCursorInfo.IsEmpty) return false; if (!diagramPresenter.Project.SecurityManager.IsGranted(Permission.Layout, diagramPresenter.SelectedShapes)) return false; if (!shapeAtCursorInfo.Shape.HasControlPointCapability(shapeAtCursorInfo.ControlPointId, ControlPointCapabilities.Rotate)) return false; if (diagramPresenter.SelectedShapes.Count > 1) { // check if all selected shapes have a rotate handle foreach (Shape selectedShape in diagramPresenter.SelectedShapes) { bool shapeHasRotateHandle = false; foreach (ControlPointId ptId in selectedShape.GetControlPointIds(ControlPointCapabilities.Rotate)) { shapeHasRotateHandle = true; break; } if (!shapeHasRotateHandle) return false; } } return true; }
/// <summary> /// Decide which tool action is suitable for the current mouse state. /// </summary> private Action DetermineMouseMoveAction(IDiagramPresenter diagramPresenter, MouseState mouseState, ShapeAtCursorInfo shapeAtCursorInfo) { switch (CurrentAction) { case Action.None: case Action.MoveHandle: case Action.MoveShape: case Action.SelectWithFrame: // Do not change the current action return CurrentAction; case Action.Select: case Action.EditCaption: if (mouseState.IsButtonDown(MouseButtonsDg.Left)) { // Check if cursor is over a control point and moving grips or rotating is feasible if (SelectedShapeAtCursorInfo.IsCursorAtGrip) { if (IsMoveHandleFeasible(diagramPresenter, SelectedShapeAtCursorInfo)) return Action.MoveHandle; else if (IsRotatatingFeasible(diagramPresenter, SelectedShapeAtCursorInfo)) return Action.PrepareRotate; else return Action.SelectWithFrame; } else { // If there is no shape under the cursor, start a SelectWithFrame action, // otherwise start a MoveShape action bool canMove = false; if (!SelectedShapeAtCursorInfo.IsEmpty) { // If there are selected shapes, check these shapes... canMove = IsMoveShapeFeasible(diagramPresenter, mouseState, SelectedShapeAtCursorInfo); } else { // ... otherwise check the shape under the cursor as it will be selected // before starting a move action canMove = IsMoveShapeFeasible(diagramPresenter, mouseState, shapeAtCursorInfo); } if (canMove) return Action.MoveShape; else return Action.SelectWithFrame; } } return CurrentAction; case Action.PrepareRotate: if (mouseState.IsButtonDown(MouseButtonsDg.Left)) { // If the mouse has left the min rotate range, start 'real' rotating if (IsMinRotateRangeExceeded(diagramPresenter, mouseState)) return Action.Rotate; else return CurrentAction; } else return CurrentAction; case Action.Rotate: if (mouseState.IsButtonDown(MouseButtonsDg.Left)) { // If the mouse has entered the min rotate range, start showing rotating hint if (!IsMinRotateRangeExceeded(diagramPresenter, mouseState)) return Action.PrepareRotate; else return CurrentAction; } else return CurrentAction; default: throw new NShapeUnsupportedValueException(CurrentAction); } }