private void Render() { if (TracePoints != null && TracePoints.Count > 2) { PointF[] polygon = CreateSelectionPolygon(); if (polygon.Length > 2) { DocumentWorkspace.ResetOutlineWhiteOpacity(); NewSelectionRenderer.ResetOutlineWhiteOpacity(); Selection.SetContinuation(polygon, SelectionMode); CombineMode cm; if (SelectionMode == CombineMode.Replace) { cm = CombineMode.Replace; } else { cm = CombineMode.Xor; } NewSelection.SetContinuation(polygon, cm); Update(); } } }
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(); 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 selection, 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 = Name; HistoryStack.PushNewMemento(UndoAction); Selection.CommitContinuation(); break; case WhatToDo.Reset: // reset selection, no HistoryMemento Selection.ResetContinuation(); break; } DocumentWorkspace.ResetOutlineWhiteOpacity(); NewSelectionRenderer.ResetOutlineWhiteOpacity(); NewSelection.Reset(); NewSelectionRenderer.Visible = false; Tracking = false; DocumentWorkspace.EnableSelectionOutline = true; DocumentWorkspace.InvalidateSurface(Utility.RoundRectangle(DocumentWorkspace.VisibleDocumentRectangleF)); } }
protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); Cursor = GetCursor(); if (Tracking) { MoveOriginMode = true; LastPoint = new Point(e.X, e.Y); OnMouseMove(e); } else if ((e.Button & MouseButtons.Left) == MouseButtons.Left || (e.Button & MouseButtons.Right) == MouseButtons.Right) { Tracking = true; HasMoved = false; StartTime = DateTime.Now; TracePoints = new List <Point> { new Point(e.X, e.Y) }; UndoAction = new SelectionHistoryMemento("sentinel", Image, DocumentWorkspace); WasNotEmpty = !Selection.IsEmpty; // Determine this.combineMode if ((ModifierKeys & Keys.Control) != 0 && e.Button == MouseButtons.Left) { SelectionMode = CombineMode.Union; } else if ((ModifierKeys & Keys.Alt) != 0 && e.Button == MouseButtons.Left) { SelectionMode = CombineMode.Exclude; } else if ((ModifierKeys & Keys.Control) != 0 && e.Button == MouseButtons.Right) { SelectionMode = CombineMode.Xor; } else if ((ModifierKeys & Keys.Alt) != 0 && e.Button == MouseButtons.Right) { SelectionMode = CombineMode.Intersect; } else { SelectionMode = AppEnvironment.SelectionCombineMode; } DocumentWorkspace.EnableSelectionOutline = false; NewSelection.Reset(); PdnGraphicsPath basePath = Selection.CreatePath(); NewSelection.SetContinuation(basePath, CombineMode.Replace, true); NewSelection.CommitContinuation(); bool newSelectionRendererVisible = true; // Act on this.combineMode switch (SelectionMode) { case CombineMode.Xor: Append = true; Selection.ResetContinuation(); break; case CombineMode.Union: Append = true; Selection.ResetContinuation(); break; case CombineMode.Exclude: Append = true; Selection.ResetContinuation(); break; case CombineMode.Replace: Append = false; Selection.Reset(); break; case CombineMode.Intersect: Append = true; Selection.ResetContinuation(); break; default: throw new InvalidEnumArgumentException(); } NewSelectionRenderer.Visible = newSelectionRendererVisible; } }