Skip to content

Chord-click selects one note or the whole strum, per profile - #297

Merged
byrongamatos merged 1 commit into
mainfrom
feat/editor-chord-select-profile
Jul 16, 2026
Merged

Chord-click selects one note or the whole strum, per profile#297
byrongamatos merged 1 commit into
mainfrom
feat/editor-chord-select-profile

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Why

Clicking one note of a chord in a guitar/bass part selected the whole strum — every same-time note — which is a genuine "wait, what?" moment in a piano-roll-style editor. Notably the editor already selects a single note in piano-roll (keys) parts; only the fretted parts force-grouped.

Rather than pick a universal winner, this makes chord-click selection profile-driven, exactly like the existing right-click behaviour (_editorDefaultRightClickBehaviorPure → EOF vs context). So the DAW-flavoured profiles feel like a DAW, and Legacy (EOF) stays EOF-faithful.

What

  • FeedBack / Logical / Cableton → select the single note under the cursor (DAW-faithful; matches keys parts).
  • Legacy (EOF) → keep the whole-strum unit — EOF treats the position as the atomic selectable thing.
  • Alt-click always inverts the default, so grabbing one note or the whole chord is one keystroke away in any profile.
  • Sustain-resize reads the same one decision (_editorChordGrabsStrumPure), so a click and an edge-drag can never disagree about what a grab means. (This flips resize in the DAW profiles from its old chord-default to single-default — the intended consistency win.)
  • A Chord click toggle in the shortcut panel (?) pins it regardless of profile, persisted to localStorage (editor.chordSelect) the same way editor.rightClickBehavior is.
  • Keys DATA is unchanged — same-time notes there are independent voices and always select one.

Design notes

The profile default → explicit override → Alt inversion → keys-DATA exemption all fold into one pure helper (_editorChordGrabsStrumPure) that both grab paths in mouse.js call, so there's a single source of truth for "does this grab act on the strum?"

Tests

tests/chord_select_behavior.test.mjs — new .test.mjs unit suite over the three pure resolvers (default, effective-with-override, and the grab decision incl. Alt inversion + keys exemption + boolean coercion). Fails on main (the resolvers don't exist there). Full JS suite (186) + pytest-free (no routes.py change) + npm run lint (0 errors) all green.

Docs

CHANGELOG [Unreleased] + USER-GUIDE §4 (Edit notes) updated.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added configurable chord-click selection, allowing users to select either a single note or the entire chord.
    • Added Alt-click to temporarily switch between selection modes.
    • Sustain resizing now follows the same chord-selection behavior.
    • Added a “Chord click” option to the shortcut settings panel.
    • Piano-roll note selection remains unchanged.
  • Documentation

    • Updated the user guide and changelog with the new selection behavior and configuration details.
  • Tests

    • Added coverage for profile defaults, overrides, Alt-click behavior, and special cases.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Chord-click selection now follows shortcut-profile defaults or a persisted override. Alt-click reverses the mode, sustain resizing uses the same grouping decision, and keys-data clicks remain ungrouped. The shortcut panel, global API, documentation, changelog, and helper tests are updated.

Changes

Chord selection behavior

Layer / File(s) Summary
Behavior settings and controls
src/shortcuts.js, screen.html, src/main.js, tests/chord_select_behavior.test.mjs, CHANGELOG.md, docs/USER-GUIDE.md
Profile-based defaults, saved overrides, Alt inversion, UI synchronization, global setter wiring, documentation, and pure-helper tests are added.
Mouse selection and resizing
src/mouse.js
Note clicks and sustain edge grabs use the resolved groupChord decision for same-time chord siblings and resize targets.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ShortcutPanel
  participant Main as src/main.js
  participant Shortcuts as src/shortcuts.js
  participant Mouse as src/mouse.js
  participant Notes as NoteSelection
  ShortcutPanel->>Main: Set chord-click behavior
  Main->>Shortcuts: Persist and synchronize behavior
  Mouse->>Shortcuts: Resolve profile, override, and Alt state
  Shortcuts-->>Mouse: Return groupChord
  Mouse->>Notes: Select note or same-time chord siblings
Loading

Possibly related PRs

Suggested reviewers: byrongamatos

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: profile-driven chord-click selection between single note and whole strum.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/editor-chord-select-profile

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mouse.js (1)

184-207: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make Alt-click isolate an already-selected chord note.

When a whole chord is selected, Alt-clicking one of its selected notes sets groupChord to false, but Line 204 still skips reselection because idx is already selected. The subsequent move drag therefore still contains the entire chord, violating the documented inversion behavior.

Preserve the Keys DATA exemption, but collapse non-keys multi-selection to idx when groupChord is false.

Suggested fix
-    const groupChord = _editorChordGrabsStrumPure(_chordSel, e.altKey, isKeysArr());
+    const keysData = isKeysArr();
+    const groupChord = _editorChordGrabsStrumPure(_chordSel, e.altKey, keysData);
...
-        } else if (!S.sel.has(idx)) {
+        } else if (!S.sel.has(idx) || (!groupChord && !keysData && S.sel.size > 1)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mouse.js` around lines 184 - 207, Update the click-selection logic around
groupChord and the `!S.sel.has(idx)` branch so that non-Keys DATA Alt-clicks
with `groupChord` false collapse the selection to `idx` even when that note is
already selected. Preserve the existing whole-chord toggle and selection
behavior when `groupChord` is true, along with the Keys DATA exemption.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/mouse.js`:
- Around line 184-207: Update the click-selection logic around groupChord and
the `!S.sel.has(idx)` branch so that non-Keys DATA Alt-clicks with `groupChord`
false collapse the selection to `idx` even when that note is already selected.
Preserve the existing whole-chord toggle and selection behavior when
`groupChord` is true, along with the Keys DATA exemption.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16c4ae12-78b4-4eda-8333-c02c47832e7b

📥 Commits

Reviewing files that changed from the base of the PR and between 35b7632 and 62fc462.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • docs/USER-GUIDE.md
  • screen.html
  • src/main.js
  • src/mouse.js
  • src/shortcuts.js
  • tests/chord_select_behavior.test.mjs

@byrongamatos
byrongamatos force-pushed the feat/editor-chord-select-profile branch from 62fc462 to 408d8b6 Compare July 16, 2026 18:49
@byrongamatos
byrongamatos merged commit 880f766 into main Jul 16, 2026
3 checks passed
@byrongamatos
byrongamatos deleted the feat/editor-chord-select-profile branch July 16, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants