Skip to content

Reliable selection and editing controls - #522

Merged
mudabs merged 7 commits into
oss-slu:mainfrom
Remex9:feature/439-selection-editing-controls
Nov 9, 2026
Merged

mudabs merged 7 commits into
oss-slu:mainfrom
Remex9:feature/439-selection-editing-controls

Conversation

@Remex9

@Remex9 Remex9 commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Summary

Closes #439, Closes #440, Closes #441, Closes #442, Closes #443, Closes #444

Selection and editing in the Scene Editor now work reliably in crowded scenes. Images and annotations share one selection, which can be made with the mouse or the keyboard. Clicking again in the same spot reaches objects hidden under others. A drag only ever moves the selected object. Edits can be undone and redone, and leaving the editor with unsaved changes now asks first.

PR Checklist

  • Project builds and runs (each feature checked in the browser)
  • Tests and linters pass (npx jest: 856 passed, 5 skipped; npm run lint clean)
  • Any related documentation has been updated, including JSDoc comments or docstrings

Detailed Description

Selection (#440, #441)

  • One state.selection replaces the separate image and annotation selections. Escape or a click on empty canvas clears it, and Tab / Shift+Tab step through objects. Each selection is announced.
  • objectsAt(scene, point) in sceneCanvas.js lists every object under a point, topmost first. Clicking again in the same spot (or Alt+click) selects the next object down, and a hint shows when objects overlap.
  • The canvas stays in place when the toolbar appears above it, so a second click lands where the first one did.

Editing (#442, #443)

  • A drag anywhere on the selected object moves it, even where something covers it. Unselected objects never move.
  • Images can be moved with the arrow keys and deleted with Delete/Backspace, the same as annotations.
  • Undo/Redo buttons, plus Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z or Ctrl+Y. A run of typing or nudges undoes as one step, and undoing back to the saved version shows "Saved" again. History resets when another scene is opened.

Unsaved changes (#444)

  • Back, the Scene Editor button, and the "view in bone viewer" links ask before leaving with unsaved changes. Leaving keeps the working copy.

Tests

  • New tests in sceneCanvas.test.js and sceneAnnotationEditor.test.js for each issue. In scenes.test.js, one test now expects a second click to keep an image selected instead of deselecting it.

Known limitation: image drags store unrounded coordinates, and the selection outline doesn't match a cropped image that is also flipped.

Remex9 and others added 6 commits November 2, 2026 14:57
- Replace the separate image and annotation selection fields with one
  `state.selection` ({ kind, index } or null) behind select/deselect helpers.
- Clicking an object selects it; clicking it again keeps it selected (the
  second click is reserved for reaching overlapping objects in oss-slu#441).
  Clicking a resize or crop handle without dragging no longer deselects.
- Escape or a click on empty canvas clears the selection for every object type.
- Tab / Shift+Tab on the canvas step through drawn objects from the top of
  the stack down; past either end the selection clears and focus leaves.
- Each selection is announced with its type, label text, and stack position.

Part of oss-slu#439.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add objectsAt(scene, point) to sceneCanvas.js: every drawn object under a
  scene point, topmost first, matching what renderScene draws (rotated and
  flipped crop areas, line hit width, polygon fill, linked annotations, and
  colored regions clipped to their image's crop).
- Clicking again in the same spot selects the next object down the stack,
  wrapping back to the top; Alt+click steps down from anywhere on the stack.
  A click in a new spot selects the topmost object there.
- While objects overlap, a hint under the canvas (also announced) says how
  many there are and how to reach the next one; it clears on any edit.
- Selecting or clearing keeps the canvas in place on screen, so the toolbar
  that appears above it no longer moves the scene out from under the pointer.
- A double-click only opens a label's text when the clicks left that label
  selected, so quick clicks keep stepping down the stack.

Part of oss-slu#439.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A press anywhere on the selected object drags it, even where another
  object is drawn over it (an image reached under a highlight with oss-slu#441's
  click-again); a press on any unselected object never moves anything.
- The selected image now has the same keyboard controls as annotations:
  arrow keys move it by 1 scene pixel (10 with Shift), and Delete or
  Backspace removes it (announced). Both are off while a crop is edited.
- Tests cover a crowded scene: dragging, nudging, and resizing a covered
  image, then saving and reopening; drags on unselected objects moving
  nothing; a selected highlight moving under the label drawn on it; and
  deleting images from the keyboard.

Part of oss-slu#439.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on-editing-controls

# Conflicts:
#	templates/js/scenes.js
#	templates/tests/sceneAnnotationEditor.test.js
- Every recorded change to the working copy (images, annotations, and the
  import log) becomes an undo step, up to 100. Image src strings, which can
  be megabytes of base64, are shared between steps rather than copied.
- A run of small edits of one kind on one object - typing a label, picking a
  color, dragging the opacity slider, nudging with the arrow keys - undoes as
  one step; selecting another object or saving starts a new step.
- Revisions now only count up, so undoing or redoing back to the saved
  version shows "Saved" again, and a new edit after an undo never looks saved.
- Undo and Redo buttons next to Save, plus Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z or
  Ctrl+Y; text fields keep their own undo. Each step is announced.
- The selected object stays selected if it still exists. History is cleared
  when another scene is opened or a version is reloaded, so undo never
  reaches into another scene.

Part of oss-slu#439.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The Back button, pressing Scene Editor again, and a scene's "view in the
  bone viewer" links now ask before leaving when the open scene has unsaved
  changes. Choosing to stay keeps the editor open (announced); choosing to
  leave keeps the working copy, which is still there on coming back.
- With everything saved, the editor is left without asking, as before.
- Closing or reloading the page, opening another scene, New, Delete, and
  Duplicate already warned (oss-slu#507); this closes the remaining gap.

Part of oss-slu#439.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@mudabs mudabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Remex9 for bringing the selection, overlapping-object navigation, image editing, undo/redo, and unsaved-change protections together in PR #522. The implementation has strong coverage, and the GitHub checks, Sonar quality gate, lint, and local test suite all pass.

Please address the following before approval:

  • Restore keyboard focus to the canvas after selecting an object.
    • templates/js/scenes.js around selectObject() at line 1776 and handleSelectClick() at line 1819 redraw the scene but do not focus #scene-canvas.
    • templates/boneset.html makes #scene-canvas the only focusable editing surface with tabindex="0".
    • In browser testing, clicking a selected label left focus in the annotation text field instead of moving it to the canvas.
    • As a result, Arrow, Delete, and Backspace shortcuts may not work after selecting an image or annotation with the mouse or pointer.
    • Focus the canvas after selection while preserving the existing behavior that returns focus to the text field when editing a label.
  • Add a regression test for the real focus path.
    • Select an image or annotation through a browser-style click.
    • Verify that document.activeElement becomes #scene-canvas.
    • Confirm that Arrow and Delete or Backspace then modify the selected object.
    • The current tests dispatch keyboard events directly to #scene-canvas, so they do not catch this focus issue.
      Please rerun:
  • npm run lint
  • git diff --check
  • npm test -- --runInBand

A press on an object can start a drag, which cancels the browser's own
focus change, so focus stayed in the label's text field and the arrow
keys and Delete didn't reach the canvas. The canvas now takes focus on
each selecting click; a double-click on a label still opens its text.

Adds tests that send keys to the focused element after a real click.
@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

@Remex9
Remex9 requested a review from mudabs November 9, 2026 17:27

@mudabs mudabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Remex9 addressing the focus issue in PR #522.

  • The canvas now receives focus after selecting an object.
  • Keyboard actions such as Arrow, Delete, and Backspace work after mouse selection.
  • Double-clicking a label still correctly returns focus to its text field.
  • New tests verify the real browser-style focus path.
  • GitHub checks pass.
  • Local validation passed: 22 suites, 858 tests passed, 5 skipped.

I did not find any remaining blocking issues. This PR is ready for approval.

@mudabs
mudabs merged commit 602e9c5 into oss-slu:main Nov 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants