From c5b6328f8526355dd4be3ad996c2709b06e0cae9 Mon Sep 17 00:00:00 2001 From: Erik Demaine Date: Sun, 13 Nov 2022 12:28:25 -0500 Subject: [PATCH] Arrow keys for nudging anchor selection (#214) --- client/Anchor.coffee | 32 ++++++++++++++++++++++++++++++++ client/Board.coffee | 1 + client/DrawApp.coffee | 14 ++++++++++---- client/tools/modes.coffee | 4 ++-- doc/README.md | 6 +++++- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/client/Anchor.coffee b/client/Anchor.coffee index 55c00d5..6c9390a 100644 --- a/client/Anchor.coffee +++ b/client/Anchor.coffee @@ -1,3 +1,5 @@ +import {undoStack} from './UndoStack' + export anchorRadius = 4 export anchorStroke = 2 #export anchorVisualRadius = anchorRadius + anchorStroke / 2 @@ -68,6 +70,10 @@ export decodeAnchor = (elt) -> export class AnchorSelection constructor: (@board) -> @selected = {} + nonempty: -> + for id of @selected # eslint-disable-line coffee/no-unused-vars + return true + false has: (id, index) -> {id, index} = id if id.id? @selected[id]?[index]? @@ -98,8 +104,34 @@ export class AnchorSelection @add id, index ids: -> id for id of @selected + objs: -> + for id in @ids() + obj = Objects.findOne id + continue unless obj? + obj clear: -> for id, indices of @selected for index of indices @board.render?.anchors?[id]?[index]?.classList.remove 'select' @selected = {} + + translate: ({x, y}) -> + return if @board.readonly + return unless x or y + objs = @objs() + return unless objs.length + undoStack.pushAndDo + type: 'multi' + ops: + for obj in objs + before = pts: obj.pts + after = pts: obj.pts[..] + anchors = anchorsOf obj + for index in @indicesForId obj._id + anchorMove obj, after.pts, index, + x: anchors[index].x + x + y: anchors[index].y + y + type: 'edit' + id: obj._id + before: before + after: after diff --git a/client/Board.coffee b/client/Board.coffee index f395e46..0642e65 100644 --- a/client/Board.coffee +++ b/client/Board.coffee @@ -36,6 +36,7 @@ export class Board @transform = defaultTransform() @selection = new Selection @ @anchorSelection = new AnchorSelection @ + @selections = [@selection, @anchorSelection] ## Map from Object `_id` to a `Highlighter` instance ## that is currently highlighting that object. @highlighters = {} diff --git a/client/DrawApp.coffee b/client/DrawApp.coffee index 81e072d..992e3b2 100644 --- a/client/DrawApp.coffee +++ b/client/DrawApp.coffee @@ -252,20 +252,26 @@ export DrawAppRoom = -> when 'Escape' if currentBoard()?.selection?.nonempty() currentBoard().selection.clear() + else if currentBoard()?.anchorSelection?.nonempty() + currentBoard().anchorSelection.clear() else if historyMode() setHistoryMode false # escape history view by toggling when 'ArrowLeft' delta = if e.shiftKey then 0.5 else 1 - currentBoard()?.selection?.translate gridOffset -delta, 0 + for selection in currentBoard()?.selections ? [] + selection.translate gridOffset -delta, 0 when 'ArrowRight' delta = if e.shiftKey then 0.5 else 1 - currentBoard()?.selection?.translate gridOffset +delta, 0 + for selection in currentBoard()?.selections ? [] + selection.translate gridOffset +delta, 0 when 'ArrowUp' delta = if e.shiftKey then 0.5 else 1 - currentBoard()?.selection?.translate gridOffset 0, -delta + for selection in currentBoard()?.selections ? [] + selection.translate gridOffset 0, -delta when 'ArrowDown' delta = if e.shiftKey then 0.5 else 1 - currentBoard()?.selection?.translate gridOffset 0, +delta + for selection in currentBoard()?.selections ? [] + selection.translate gridOffset 0, +delta else ## Prevent e.g. ctrl-1 browser shortcut (go to tab 1) from also ## triggering width 1 hotkey. diff --git a/client/tools/modes.coffee b/client/tools/modes.coffee index 345093e..64d01ea 100644 --- a/client/tools/modes.coffee +++ b/client/tools/modes.coffee @@ -125,7 +125,7 @@ defineTool category: 'mode' icon: 'mouse-pointer' hotspot: [0.21875, 0.03515625] - help: <>Select objects by dragging rectangle or clicking on individual objects (toggling multiple if holding Shift). Then change their color/width, move by dragging (Shift for horizontal/vertical) or using arrow keys, copy via {Ctrl}-C, cut via {Ctrl}-X, paste via {Ctrl}-V, duplicate via {Ctrl}-D, or Delete them. + help: <>Select objects by dragging rectangle or clicking on individual objects (toggling multiple if holding Shift). Then change their color/width, move by dragging (Shift for horizontal/vertical) or using arrow keys (Shift for half-grid), copy via {Ctrl}-C, cut via {Ctrl}-X, paste via {Ctrl}-V, duplicate via {Ctrl}-D, or Delete them. hotkey: 's' start: -> pointers.objects = {} @@ -281,7 +281,7 @@ defineTool category: 'mode' icon: 'anchor-select' hotspot: [0.31, 0.16992] - help: <>Select anchor handles to reshape lines, rectangles, and ellipses. Drag anchor to move it; or drag rectangle or click on individual anchors (toggling multiple if holding Shift) and then drag to move (Shift for horizontal/vertical). + help: <>Select anchor handles to reshape lines, rectangles, and ellipses. Drag anchor to move it; or drag rectangle or click on individual anchors (toggling multiple if holding Shift) and then move by dragging (Shift for horizontal/vertical) or using arrow keys (Shift for half-grid). hotkey: 'a' start: -> mainBoard.showAnchors true diff --git a/doc/README.md b/doc/README.md index f3284da..f6dd249 100644 --- a/doc/README.md +++ b/doc/README.md @@ -228,7 +228,7 @@ purely horizontal or vertical. You can also nudge objects horizontally or vertically using the arrow keys. Normally, objects move by one grid unit. -If you hold Shift while pressing the keys, +If you hold Shift while pressing arrow keys, the move is by half-grid units. **Cut/copy/paste/duplicate/delete.** @@ -279,6 +279,10 @@ You can select multiple anchors in two ways: You can then move the selected anchors by dragging one of the selected anchors, or dragging an additional anchor to select while holding Shift. +Alternatively, you can nudge objects horizontally or vertically +using the arrow keys. Normally, objects move by one grid unit. +If you hold Shift while pressing arrow keys, +the move is by half-grid units. ### Pen Icon Pen Tool