17class EditGestureIdentityIssueTestAccess;
74 std::optional<timeline::Clip>
clip;
117std::optional<timeline::ModelError>
121class ValidatedNoteEditIntent {
132 bool operator==(
const ValidatedNoteEditIntent& other)
const noexcept {
133 return value_ == other.value_;
139 NoteEditIntent value_;
222 : identity_(std::exchange(other.identity_, {})),
224 provenance_(std::exchange(other.provenance_, {})) {}
237 : identity_(std::move(identity)), phase_(
phase), provenance_(provenance) {}
242 std::span<const timeline::NoteEvent> current_notes)
const;
244 void invalidate() noexcept {
250 EditIntentIdentity identity_;
252 timeline::WriterToken::Provenance provenance_;
282 const auto provenance = writer.provenance();
283 if (!provenance.valid())
287 const auto undo_group = writer.allocate_undo_group_id();
300 : provenance_(std::exchange(other.provenance_, {})),
301 undo_group_(std::exchange(other.undo_group_, {})),
303 pending_(std::exchange(other.pending_,
false)),
304 pending_transaction_(std::exchange(other.pending_transaction_, {})),
305 pending_revision_(std::exchange(other.pending_revision_, {})),
306 pending_command_(std::exchange(other.pending_command_, {})),
324 if (!writer.provenance().valid())
326 if (writer.provenance() != provenance_)
328 if (!phase_permitted(phase))
331 const auto transaction_id = writer.allocate_transaction_id();
332 if (!transaction_id.valid()) {
337 const auto command_id = writer.allocate_command_id();
338 if (!command_id.valid()) {
343 EditIntentIdentity identity{transaction_id, expected_revision, command_id, undo_group_};
345 pending_transaction_ = transaction_id;
346 pending_revision_ = expected_revision;
347 pending_command_ = command_id;
348 pending_phase_ = phase;
363 if (!matches_pending(
issue))
365 if (!writer.provenance().valid())
367 if (writer.provenance() != provenance_)
370 auto transaction =
issue.lower(std::move(intent));
372 return lowering_error(transaction.error());
374 return submit_lowered(session, writer,
issue, std::move(*transaction));
381 std::span<const timeline::NoteEvent> current_notes) {
382 if (!matches_pending(
issue))
384 if (!writer.provenance().valid())
386 if (writer.provenance() != provenance_)
389 auto transaction =
issue.lower(std::move(intent), current_notes);
391 return note_lowering_error(transaction.error());
393 return submit_lowered(session, writer,
issue, std::move(*transaction));
414 : provenance_(provenance), undo_group_(
undo_group) {}
423 bool matches_pending(
const EditGestureIdentityIssue&
issue)
const noexcept {
424 const auto& identity =
issue.identity_;
425 return pending_ &&
issue.provenance_ == provenance_ &&
issue.phase_ == pending_phase_ &&
426 identity.transaction_id == pending_transaction_ &&
427 identity.expected_revision == pending_revision_ &&
428 identity.command_id == pending_command_ && identity.undo_group == undo_group_;
437 runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>
438 submit_lowered(timeline::DocumentSession& session, timeline::WriterToken& writer,
439 EditGestureIdentityIssue&
issue, timeline::Transaction transaction) {
440 const auto phase = pending_phase_;
441 const auto command = pending_command_;
442 auto document_result = session.submit(writer, std::move(transaction));
445 if (document_result) {
446 if (document_result->applied_commands.size() != 1 ||
447 document_result->applied_commands.front() != command ||
448 !session.is_current_publication(*document_result)) {
450 state_ = session.is_gesture_open(provenance_, undo_group_)
453 return submission_result_error(std::move(*document_result));
455 state_ = committed_state_after(phase);
457 return runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>(
runtime::Ok(
458 EditGestureSubmitOutcome{std::move(document_result), state_}));
461 void clear_pending() noexcept {
463 pending_transaction_ = {};
464 pending_revision_ = {};
465 pending_command_ = {};
469 static runtime::Result<EditGestureIdentityIssue, EditGestureIdentityError>
471 return runtime::Result<EditGestureIdentityIssue, EditGestureIdentityError>(
475 static runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>
477 return runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>(
482 static runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>
483 lowering_error(timeline::ModelError error) {
484 return runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>(
runtime::Err(
486 std::nullopt, std::nullopt}));
489 static runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>
491 return runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>(
runtime::Err(
493 std::nullopt, std::nullopt,
error}));
496 static runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>
497 submission_result_error(timeline::CommitResult result) {
498 return runtime::Result<EditGestureSubmitOutcome, EditGestureSubmitError>(
runtime::Err(
500 std::nullopt, std::move(result), std::nullopt}));
503 timeline::WriterToken::Provenance provenance_;
504 timeline::UndoGroupId undo_group_;
506 bool pending_ =
false;
507 timeline::TransactionId pending_transaction_;
508 timeline::DocumentRevision pending_revision_;
509 timeline::CommandId pending_command_;
560 std::span<const timeline::NoteEvent> current_notes,
574EditGestureIdentityIssue::lower(
EditIntent intent)
const {
575 intent.
phase = phase_;
580EditGestureIdentityIssue::lower(ValidatedNoteEditIntent intent,
581 std::span<const timeline::NoteEvent> current_notes)
const {
582 auto value = intent.value();
583 value.phase = phase_;
Wrap a value as a failure result.
Definition result.hpp:58
Wrap a value as a success result.
Definition result.hpp:42
Result<T, E> — either holds a T or an E, never both.
Definition result.hpp:76
Thread-safe owner of a revisioned Timeline document.
Definition document_session.hpp:414
Opaque identity of one writer authority within one document session.
Definition document_session.hpp:340
Move-only authority for submitting transactions to one DocumentSession.
Definition document_session.hpp:334
Allocates one undo group and submits a construction-safe stream of gesture identities.
Definition edit_intent.hpp:277
EditGestureIdentityAllocator(EditGestureIdentityAllocator &&other) noexcept
Transfers allocator lifecycle and invalidates other.
Definition edit_intent.hpp:299
static runtime::Result< EditGestureIdentityAllocator, EditGestureIdentityError > create(timeline::WriterToken &writer) noexcept
Allocates the gesture's sole undo group at pointer-down.
Definition edit_intent.hpp:281
runtime::Result< EditGestureSubmitOutcome, EditGestureSubmitError > submit(timeline::DocumentSession &session, timeline::WriterToken &writer, EditGestureIdentityIssue &&issue, EditIntent intent)
Lowers and submits exactly one issued gesture intent.
Definition edit_intent.hpp:361
runtime::Result< EditGestureSubmitOutcome, EditGestureSubmitError > submit(timeline::DocumentSession &session, timeline::WriterToken &writer, EditGestureIdentityIssue &&issue, ValidatedNoteEditIntent intent, std::span< const timeline::NoteEvent > current_notes)
Lowers and submits one note gesture using this allocator's opaque identity.
Definition edit_intent.hpp:379
bool has_pending_identity() const noexcept
Returns whether one issued identity still needs submission.
Definition edit_intent.hpp:407
EditGestureIdentityAllocator & operator=(EditGestureIdentityAllocator &&)=delete
runtime::Result< EditGestureIdentityIssue, EditGestureIdentityError > issue(timeline::WriterToken &writer, timeline::DocumentRevision expected_revision, timeline::GesturePhase phase) noexcept
Issues fresh transaction and command IDs for one legal lifecycle step.
Definition edit_intent.hpp:316
EditGestureIdentityAllocator & operator=(const EditGestureIdentityAllocator &)=delete
EditGestureIdentityState state() const noexcept
Returns the last submission-confirmed lifecycle state.
Definition edit_intent.hpp:402
EditGestureIdentityAllocator(const EditGestureIdentityAllocator &)=delete
timeline::UndoGroupId undo_group() const noexcept
Returns the one undo group shared by every issue from this allocator.
Definition edit_intent.hpp:397
One opaque, single-owner identity issue awaiting a submission outcome.
Definition edit_intent.hpp:216
EditGestureIdentityIssue & operator=(const EditGestureIdentityIssue &)=delete
EditGestureIdentityIssue(EditGestureIdentityIssue &&other) noexcept
Transfers the pending identity and invalidates other.
Definition edit_intent.hpp:221
EditGestureIdentityIssue(const EditGestureIdentityIssue &)=delete
EditGestureIdentityIssue & operator=(EditGestureIdentityIssue &&)=delete
timeline::GesturePhase phase() const noexcept
Returns the authoritative phase used when the allocator submits this issue.
Definition edit_intent.hpp:228
friend class EditGestureIdentityAllocator
Definition edit_intent.hpp:233
friend class detail::EditGestureIdentityIssueTestAccess
Definition edit_intent.hpp:234
Adds intent submission for one intent vocabulary.
Definition sequencer_ui_host.hpp:213
A note intent that passed validate_note_edit_intent and may cross a host seam.
Definition edit_intent.hpp:121
const NoteEditIntent & value() const noexcept
Returns the immutable validated value retained by this wrapper.
Definition edit_intent.hpp:128
static runtime::Result< ValidatedNoteEditIntent, timeline::ModelError > create(NoteEditIntent intent) noexcept
Validates and owns one complete intent, or returns its first error.
bool operator==(const ValidatedNoteEditIntent &other) const noexcept
Definition edit_intent.hpp:132
runtime::Result< timeline::Transaction, NoteLoweringError > lower_note_edit_intent(const ValidatedNoteEditIntent &intent, std::span< const timeline::NoteEvent > current_notes, const EditIntentIdentity &identity)
Lowers one note intent to the granular transaction that performs it.
GesturePhase
Lifecycle position of a transaction within an interactive gesture.
Definition command.hpp:79
std::optional< timeline::ModelError > validate_note_edit_intent(const NoteEditIntent &intent) noexcept
Returns the first structural or note-domain error, or nullopt when valid.
EditIntentKind
What an editing gesture does to the document.
Definition edit_intent.hpp:31
SequencerUiHostT< EditIntent > EditIntentHost
The host an editor submits its intents to.
Definition edit_intent.hpp:523
NoteLoweringError
Why a note intent could not be lowered to a transaction.
Definition edit_intent.hpp:529
runtime::Result< timeline::Transaction, timeline::ModelError > lower_edit_intent(const EditIntent &intent, const EditIntentIdentity &identity)
Lowers one intent to the ordinary transaction that performs it.
NoteEditIntentKind
What a piano-roll gesture does to one note.
Definition edit_intent.hpp:85
EditGestureIdentityError
Why an edit-gesture identity operation was refused.
Definition edit_intent.hpp:172
SequencerUiHostT< ValidatedNoteEditIntent > NoteEditIntentHost
Host binding used by a piano-roll front-end before command lowering.
Definition edit_intent.hpp:145
EditGestureIdentityState
Confirmed lifecycle state of one continuous edit gesture.
Definition edit_intent.hpp:160
@ Update
Definition command.hpp:79
@ Begin
Definition command.hpp:79
@ Single
Definition command.hpp:79
@ End
Definition command.hpp:79
@ Cancel
Definition command.hpp:79
@ Draw
Create a clip. Lowers to InsertClip.
Definition edit_intent.hpp:32
@ Move
Reposition a clip. Lowers to MoveClip.
Definition edit_intent.hpp:34
@ Resize
Change a clip's extent. Lowers to MoveClip with a changed range.
Definition edit_intent.hpp:35
@ Erase
Delete a clip. Lowers to RemoveClip.
Definition edit_intent.hpp:33
@ InvalidIdentity
The transaction or command identity is malformed.
Definition edit_intent.hpp:539
@ NoteNotInClip
Erase or a transform named a note the supplied content does not carry.
Definition edit_intent.hpp:535
@ ContinuousGestureUnsupported
Reserved for source compatibility; granular lowering accepts every phase.
Definition edit_intent.hpp:531
@ ExpectedNoteMismatch
The expected note does not match the one the clip currently carries.
Definition edit_intent.hpp:537
@ DuplicateNoteIdentity
Insert supplied a note identity the clip already carries.
Definition edit_intent.hpp:533
@ SetVelocity
Replace a note after changing its velocity.
Definition edit_intent.hpp:90
@ Move
Replace a note after changing its start and/or pitch.
Definition edit_intent.hpp:88
@ Insert
Add replacement to the target MIDI clip.
Definition edit_intent.hpp:86
@ InvalidWriter
The supplied writer carries no valid session authority.
Definition edit_intent.hpp:174
@ ForeignOrStaleIssue
The issue is consumed, moved-from, foreign, or no longer pending.
Definition edit_intent.hpp:186
@ InvalidPhase
The requested phase is illegal for the confirmed lifecycle.
Definition edit_intent.hpp:178
@ SubmissionResultMismatch
A cached success is not the session's current publication.
Definition edit_intent.hpp:190
@ GestureClosed
The allocator already committed End or Cancel.
Definition edit_intent.hpp:180
@ IntentLoweringFailed
The supplied intent could not be lowered before session submission.
Definition edit_intent.hpp:188
@ IdentityPending
One previously issued identity still awaits submission.
Definition edit_intent.hpp:184
@ IdentityExhausted
A required writer-local identity sequence was exhausted.
Definition edit_intent.hpp:182
@ WriterMismatch
The writer does not match the allocator's opaque provenance.
Definition edit_intent.hpp:176
@ Closed
End or Cancel committed; this allocator cannot issue again.
Definition edit_intent.hpp:166
@ AwaitingBegin
No Begin has been confirmed for this allocator's group.
Definition edit_intent.hpp:162
@ Exhausted
A required writer-local identity sequence was exhausted.
Definition edit_intent.hpp:168
@ Open
A Begin or Update is confirmed and End/Cancel may be issued.
Definition edit_intent.hpp:164
@ Ok
No error; bytes is authoritative.
Definition stream.hpp:32
Definition edit_intent.hpp:16
ScriptedUiHost is a SequencerUiHost whose playhead is written by the caller instead of an engine,...
Definition edit_intent.hpp:14
Writer-scoped, monotonically assigned command identity.
Definition command.hpp:32
Monotonic document snapshot revision used for optimistic admission.
Definition command.hpp:54
Nonzero monotonic identity for a Timeline-owned object.
Definition item_id.hpp:19
Writer-scoped, monotonically assigned transaction identity.
Definition command.hpp:43
Writer-scoped identity joining gesture transactions into one undo unit.
Definition command.hpp:60
A refusal before submission, or an inconsistent successful session result.
Definition edit_intent.hpp:202
std::optional< timeline::CommitResult > commit_result
Exact committed result when code is SubmissionResultMismatch.
Definition edit_intent.hpp:208
std::optional< timeline::ModelError > model_error
Exact lowering diagnostic when code is IntentLoweringFailed.
Definition edit_intent.hpp:206
EditGestureIdentityError code
Stable category for the failed allocator operation.
Definition edit_intent.hpp:204
std::optional< NoteLoweringError > note_lowering_error
Exact note-lowering diagnostic when a note intent could not be lowered.
Definition edit_intent.hpp:210
Result of submitting one issued gesture transaction through its allocator.
Definition edit_intent.hpp:194
EditGestureIdentityState state
Confirmed allocator state after that result was applied.
Definition edit_intent.hpp:198
runtime::Result< timeline::CommitResult, timeline::TransactionError > document_result
The exact result returned by DocumentSession::submit().
Definition edit_intent.hpp:196
Identities a lowered transaction needs and an intent deliberately does not carry.
Definition edit_intent.hpp:152
std::optional< timeline::UndoGroupId > undo_group
Definition edit_intent.hpp:156
timeline::DocumentRevision expected_revision
Definition edit_intent.hpp:154
timeline::TransactionId transaction_id
Definition edit_intent.hpp:153
timeline::CommandId command_id
Definition edit_intent.hpp:155
One editing step expressed without reference to the device that produced it.
Definition edit_intent.hpp:60
timeline::ItemId track_id
Definition edit_intent.hpp:65
std::optional< timeline::ClipTimeRange > expected_range
Optimistic gate for Move / Resize: the range the front-end believes it edits.
Definition edit_intent.hpp:70
timeline::ItemId sequence_id
Definition edit_intent.hpp:64
std::optional< timeline::Clip > clip
Payload for Draw.
Definition edit_intent.hpp:74
timeline::ItemId clip_id
Target for Erase / Move / Resize. Draw supplies clip instead.
Definition edit_intent.hpp:67
EditIntentKind kind
Definition edit_intent.hpp:61
std::optional< timeline::ClipTimeRange > replacement_range
Requested range for Move / Resize.
Definition edit_intent.hpp:72
bool operator==(const EditIntent &other) const noexcept
timeline::GesturePhase phase
Definition edit_intent.hpp:62
One validated note editing step, independent of pointer or view geometry.
Definition edit_intent.hpp:99
timeline::GesturePhase phase
Definition edit_intent.hpp:101
bool operator==(const NoteEditIntent &other) const noexcept
timeline::ItemId track_id
Definition edit_intent.hpp:104
timeline::ItemId sequence_id
Definition edit_intent.hpp:103
NoteEditIntentKind kind
Definition edit_intent.hpp:100
std::optional< timeline::NoteEvent > expected
Definition edit_intent.hpp:107
std::optional< timeline::NoteEvent > replacement
Definition edit_intent.hpp:108
timeline::ItemId clip_id
Definition edit_intent.hpp:105