private void Render() { if (tracePoints != null && tracePoints.Count > 2) { PointF[] polygon = CreateSelectionPolygon(); if (polygon.Length > 2) { DocumentWorkspace.ResetOutlineWhiteOpacity(); this.newSelectionRenderer.ResetOutlineWhiteOpacity(); Selection.SetContinuation(polygon, this.combineMode); CombineMode cm; if (SelectionMode == CombineMode.Replace) { cm = CombineMode.Replace; } else { cm = CombineMode.Xor; } this.newSelection.SetContinuation(polygon, cm); Update(); } } }
protected override void OnPulse() { if (this.tracking) { DocumentWorkspace.ResetOutlineWhiteOpacity(); } base.OnPulse(); }
protected override void OnPulse() { if (Tracking) { DocumentWorkspace.ResetOutlineWhiteOpacity(); NewSelectionRenderer.ResetOutlineWhiteOpacity(); } base.OnPulse(); }
private void Render() { if (tracePoints != null && tracePoints.Count > 2) { PointF[] polygon = CreateSelectionPolygon(); if (polygon.Length > 2) { DocumentWorkspace.ResetOutlineWhiteOpacity(); Selection.SetContinuation(polygon, this.combineMode); Update(); } } }
private void OnMouseMoveImpl(MouseEventArgs e, StringBuilder sbLogger) { if (!this.tracking) { sbLogger.Append("1 "); Cursor cursor = this.moveToolCursor; for (int i = 0; i < this.moveNubs.Length; ++i) { sbLogger.Append("2 "); MoveNubRenderer nub = this.moveNubs[i]; sbLogger.Append("3 "); if (nub.Visible && nub.IsPointTouching(new Point(e.X, e.Y), true)) { sbLogger.Append("4 "); cursor = this.handCursor; break; } } this.Cursor = cursor; sbLogger.Append("5 "); } else { sbLogger.Append("6 "); if (this.context.currentMode != Mode.Translate) { sbLogger.Append("7 "); this.Cursor = this.handCursorMouseDown; } sbLogger.Append("8 "); Point newMouseXY = new Point(e.X, e.Y); Point newOffset = new Point(newMouseXY.X - context.startMouseXY.X, newMouseXY.Y - context.startMouseXY.Y); PreRender(); this.dontDrop = true; sbLogger.Append("9 "); Selection.PerformChanging(); using (Matrix translateMatrix = new Matrix()) { RectangleF rect; translateMatrix.Reset(); if (this.context.baseTransform != null) { Selection.SetInterimTransform(this.context.baseTransform); } Matrix interim = Selection.GetInterimTransformCopy(); switch (this.context.currentMode) { case Mode.Translate: translateMatrix.Translate((float)newOffset.X, (float)newOffset.Y, MatrixOrder.Append); break; case Mode.Rotate: rect = this.context.liftedBounds; PointF center = new PointF(rect.X + (rect.Width / 2.0f), rect.Y + (rect.Height / 2.0f)); center = Utility.TransformOnePoint(interim, center); double theta1 = Math.Atan2(context.startMouseXY.Y - center.Y, context.startMouseXY.X - center.X); double theta2 = Math.Atan2(e.Y - center.Y, e.X - center.X); double thetaDelta = theta2 - theta1; this.angleDelta = (float)(thetaDelta * (180.0f / Math.PI)); float angle = this.context.startAngle + this.angleDelta; if ((ModifierKeys & Keys.Shift) != 0) { angle = ConstrainAngle(angle); angleDelta = angle - this.context.startAngle; } translateMatrix.RotateAt(angleDelta, center, MatrixOrder.Append); this.rotateNub.Location = center; this.rotateNub.Angle = this.context.startAngle + angleDelta; break; case Mode.Scale: PointF xyAxes = GetEdgeVector(this.context.startEdge); PointF xAxis = new PointF(xyAxes.X, 0); PointF yAxis = new PointF(0, xyAxes.Y); PointF edgeX = Utility.TransformOneVector(interim, xAxis); PointF edgeY = Utility.TransformOneVector(interim, yAxis); PointF edgeXN = Utility.NormalizeVector2(edgeX); PointF edgeYN = Utility.NormalizeVector2(edgeY); PointF xu; float xulen; PointF xv; Utility.GetProjection((PointF)newOffset, edgeXN, out xu, out xulen, out xv); PointF yu; float yulen; PointF yv; Utility.GetProjection((PointF)newOffset, edgeYN, out yu, out yulen, out yv); PdnGraphicsPath startPath2 = this.context.startPath.Clone(); RectangleF sp2Bounds = startPath2.GetBounds(); PointF sp2BoundsCenter = new PointF((sp2Bounds.Left + sp2Bounds.Right) / 2.0f, (sp2Bounds.Top + sp2Bounds.Bottom) / 2.0f); float tAngle = Utility.GetAngleOfTransform(interim); bool isFlipped = Utility.IsTransformFlipped(interim); using (Matrix spm = new Matrix()) { spm.Reset(); spm.RotateAt(-tAngle, sp2BoundsCenter, MatrixOrder.Append); translateMatrix.RotateAt(-tAngle, sp2BoundsCenter, MatrixOrder.Append); startPath2.Transform(spm); } RectangleF spBounds2 = startPath2.GetBounds(); startPath2.Dispose(); startPath2 = null; float xTranslate; float yTranslate; bool allowConstrain; Edge theEdge = this.context.startEdge; // If the transform is flipped, then GetTransformAngle will return 180 degrees // even though no rotation has actually taken place. Thus we have to scratch // our head and go "hmm, let's make some adjustments to this." Otherwise stretching // the top and bottom nubs goes in the wrong direction. if (isFlipped) { theEdge = FlipEdgeVertically(theEdge); } switch (theEdge) { default: throw new InvalidEnumArgumentException(); case Edge.TopLeft: allowConstrain = true; xTranslate = -spBounds2.X - spBounds2.Width; yTranslate = -spBounds2.Y - spBounds2.Height; break; case Edge.Top: allowConstrain = false; xTranslate = 0; yTranslate = -spBounds2.Y - spBounds2.Height; break; case Edge.TopRight: allowConstrain = true; xTranslate = -spBounds2.X; yTranslate = -spBounds2.Y - spBounds2.Height; break; case Edge.Left: allowConstrain = false; xTranslate = -spBounds2.X - spBounds2.Width; yTranslate = 0; break; case Edge.Right: allowConstrain = false; xTranslate = -spBounds2.X; yTranslate = 0; break; case Edge.BottomLeft: allowConstrain = true; xTranslate = -spBounds2.X - spBounds2.Width; yTranslate = -spBounds2.Y; break; case Edge.Bottom: allowConstrain = false; xTranslate = 0; yTranslate = -spBounds2.Y; break; case Edge.BottomRight: allowConstrain = true; xTranslate = -spBounds2.X; yTranslate = -spBounds2.Y; break; } translateMatrix.Translate(xTranslate, yTranslate, MatrixOrder.Append); float newWidth = spBounds2.Width + xulen; float newHeight = spBounds2.Height + yulen; float xScale = newWidth / spBounds2.Width; float yScale = newHeight / spBounds2.Height; if (allowConstrain && (this.ModifierKeys & Keys.Shift) != 0) { ConstrainScaling(this.context.liftedBounds, spBounds2.Width, spBounds2.Height, newWidth, newHeight, out xScale, out yScale); } translateMatrix.Scale(xScale, yScale, MatrixOrder.Append); translateMatrix.Translate(-xTranslate, -yTranslate, MatrixOrder.Append); translateMatrix.RotateAt(+tAngle, sp2BoundsCenter, MatrixOrder.Append); break; default: throw new InvalidEnumArgumentException(); } this.context.deltaTransform.Reset(); this.context.deltaTransform.Multiply(this.context.liftTransform, MatrixOrder.Append); this.context.deltaTransform.Multiply(translateMatrix, MatrixOrder.Append); translateMatrix.Multiply(this.context.baseTransform, MatrixOrder.Prepend); Selection.SetInterimTransform(translateMatrix); interim.Dispose(); interim = null; } // advertise our angle of rotation to any host (i.e. mainform) that might want to use that information this.hostShouldShowAngle = this.rotateNub.Visible; this.hostAngle = -this.rotateNub.Angle; Selection.PerformChanged(); dontDrop = false; Render(newOffset, true); Update(); sbLogger.Append("a "); this.context.offset = newOffset; sbLogger.Append("b "); if (this.enableOutline) { DocumentWorkspace.ResetOutlineWhiteOpacity(); } sbLogger.Append("c "); } sbLogger.Append("d "); }
protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (tracking) { return; } bool determinedMoveMode = false; Mode newMode = Mode.Translate; Edge newEdge = Edge.None; if (Selection.IsEmpty) { SelectionHistoryMemento shm = new SelectionHistoryMemento( HistoryFunctions.SelectAllFunction.StaticName, PdnResources.GetImageResource("Icons.MenuEditSelectAllIcon.png"), DocumentWorkspace); DocumentWorkspace.History.PushNewMemento(shm); DocumentWorkspace.Selection.PerformChanging(); DocumentWorkspace.Selection.Reset(); DocumentWorkspace.Selection.SetContinuation(Document.Bounds, CombineMode.Replace); DocumentWorkspace.Selection.CommitContinuation(); DocumentWorkspace.Selection.PerformChanged(); if (e.Button == MouseButtons.Right) { newMode = Mode.Rotate; } else { newMode = Mode.Translate; } newEdge = Edge.None; determinedMoveMode = true; } DocumentWorkspace.EnableSelectionOutline = this.enableOutline; if (!context.lifted) { Lift(e); } PushContextHistoryMemento(); if (!determinedMoveMode) { DetermineMoveMode(e, out newMode, out newEdge); determinedMoveMode = true; } if (this.context.deltaTransform != null) { this.context.deltaTransform.Dispose(); this.context.deltaTransform = null; } this.context.deltaTransform = new Matrix(); this.context.deltaTransform.Reset(); if (newMode == Mode.Translate || newMode == Mode.Scale || newMode != this.context.currentMode || newMode == Mode.Rotate) { this.context.startBounds = Selection.GetBoundsF(); this.context.startMouseXY = new Point(e.X, e.Y); this.context.offset = new Point(0, 0); if (this.context.baseTransform != null) { this.context.baseTransform.Dispose(); this.context.baseTransform = null; } this.context.baseTransform = Selection.GetInterimTransformCopy(); } this.context.startEdge = newEdge; this.context.currentMode = newMode; PositionNubs(this.context.currentMode); tracking = true; this.rotateNub.Visible = (this.context.currentMode == Mode.Rotate); if (this.context.startPath != null) { this.context.startPath.Dispose(); this.context.startPath = null; } this.context.startPath = Selection.CreatePath(); this.context.startAngle = Utility.GetAngleOfTransform(Selection.GetInterimTransformReadOnly()); SelectionHistoryMemento sha1 = new SelectionHistoryMemento(this.Name, this.Image, this.DocumentWorkspace); this.currentHistoryMementos.Add(sha1); OnMouseMove(e); if (this.enableOutline) { DocumentWorkspace.ResetOutlineWhiteOpacity(); } }
private void Done() { if (tracking) { // Truth table for what we should do based on three flags: // append | moved | tooQuick | result | optimized expression to yield true // ---------+-------+----------+----------------------------------------------------------------------- // F | T | T | clear selection | !append && (!moved || tooQuick) // F | T | F | emit new selected area | !append && moved && !tooQuick // F | F | T | clear selection | !append && (!moved || tooQuick) // F | F | F | clear selection | !append && (!moved || tooQuick) // T | T | T | append to selection | append && moved // T | T | F | append to selection | append && moved // T | F | T | reset selection | append && !moved // T | F | F | reset selection | append && !moved // // append --> If the user was holding control, then true. Else false. // moved --> If they never moved the mouse, false. Else true. // tooQuick --> If they held the mouse button down for more than 50ms, false. Else true. // // "Clear selection" means to result in no selected area. If the selection area was previously empty, // then no HistoryMemento is emitted. Otherwise a Deselect HistoryMemento is emitted. // // "Reset selection" means to reset the selected area to how it was before interaction with the tool, // without a HistoryMemento. PointF[] polygon = CreateSelectionPolygon(); this.hasMoved &= (polygon.Length > 1); // They were "too quick" if they weren't doing a selection for more than 50ms // This takes care of the case where someone wants to click to deselect, but accidentally moves // the mouse. This happens VERY frequently. bool tooQuick = Utility.TicksToMs((DateTime.Now - startTime).Ticks) <= 50; // If their selection was completedly out of bounds, it will be clipped bool clipped = (polygon.Length == 0); // What the user drew had no effect on the slection, e.g. subtraction where there was nothing in the first place bool noEffect = false; WhatToDo whatToDo; // If their selection gets completely clipped (i.e. outside the image canvas), // then result in a no-op if (append) { if (!hasMoved || clipped || noEffect) { whatToDo = WhatToDo.Reset; } else { whatToDo = WhatToDo.Emit; } } else { if (hasMoved && !tooQuick && !clipped && !noEffect) { whatToDo = WhatToDo.Emit; } else { whatToDo = WhatToDo.Clear; } } switch (whatToDo) { case WhatToDo.Clear: if (wasNotEmpty) { // emit a deselect history action undoAction.Name = DeselectFunction.StaticName; undoAction.Image = DeselectFunction.StaticImage; HistoryStack.PushNewMemento(undoAction); } Selection.Reset(); break; case WhatToDo.Emit: // emit newly selected area undoAction.Name = this.Name; HistoryStack.PushNewMemento(undoAction); Selection.CommitContinuation(); break; case WhatToDo.Reset: // reset selection, no HistoryMemento Selection.ResetContinuation(); break; } DocumentWorkspace.ResetOutlineWhiteOpacity(); this.newSelectionRenderer.ResetOutlineWhiteOpacity(); this.newSelection.Reset(); this.newSelectionRenderer.Visible = false; this.tracking = false; DocumentWorkspace.EnableSelectionOutline = true; DocumentWorkspace.InvalidateSurface(Utility.RoundRectangle(DocumentWorkspace.VisibleDocumentRectangleF)); } }