Skip to content

Commit

Permalink
Animate undo/redo
Browse files Browse the repository at this point in the history
  • Loading branch information
PetrGlad committed Dec 13, 2023
1 parent 0b5710b commit 8f8d426
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 23 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,27 @@ I use Pianoteq, but that is a commercial product.

## TODO

- [ ] Organize commands, reduce diff disk usage.
- [ ] Highlight undo changes.
- [ ] Highlight undo/redo changes. Should scroll some changes into view before animation on an undo/redo command if none
are currently visible.
- [ ] Location history navigation (e.g. go to a bookmark that was visited recently), with Alt + LeftArrow / RightArrow
- [ ] Adjust tempo for selection.
- [ ] When start playing send current CC values (will help damper to take effect immediately, not on next change).
- [ ] When start playing send current CC values (will help damper to take effect immediately, not on next change).
- [ ] Time marks on stave ("minute:second" from the beginning).
- [ ] Minimize use of unwrap. The biggest contention currently is event data shared between engine and stave.
- [ ] Multi-track UI (for snippets, flight recorder, and copy/paste buffer). Can show only one at a time, though. Use
tabs?
- [ ] Show (scroll to) changing objects before undo/redo.
- [ ] Reduce number of range types (preferring util::Range?)
- [ ] Reduce number of range types (preferring util::Range?)
- [ ] Zoom to fit whole composition.
- [ ] Visual hint for out-of-view selected notes. Scroll to the earliest of the selected notes on an action, if none of
them are currently visible.
- [ ] Organize commands (keep hotkeys/actions in a collection). This should make the handle_commands easier to read and
enable to have a generated cheatsheet/help UI.
- [ ] Flight recorder (always record what is coming from the MIDI controller into a separate file).
- [ ] Copy/cut/paste.
- [ ] Optimize undo history 2: save only minimal diff instead of the whole track.
- [x] Consider TransportTime to be signed (see also StaveTime). There are too many conversions forth and back.
- [x] Reduce diff disk usage.
- [x] Consider TransportTime to be signed (see also StaveTime). There are too many conversions forth and back.
- [x] Persist bookmarks in project.
- [x] Have a separate edit-position and play-start cursors (time bookmarks), so it is easier to jump back and listen to
the modified version.
Expand Down
52 changes: 37 additions & 15 deletions src/stave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use egui::Rgba;
use ordered_float::OrderedFloat;
use serde::{Deserialize, Serialize};

use crate::changeset::Changeset;
use crate::changeset::{Changeset, EventActionsList};
use crate::common::Time;
use crate::track::{
export_smf, EventId, Level, Note, Pitch, Track, TrackEvent, TrackEventType, MAX_LEVEL,
Expand Down Expand Up @@ -661,7 +661,13 @@ impl Stave {
if response.ctx.input_mut(|i| {
i.consume_shortcut(&egui::KeyboardShortcut::new(Modifiers::CTRL, egui::Key::Z))
}) {
self.history.borrow_mut().undo(&mut vec![]); // TODO (implement) changes highlighting
let mut changes = vec![];
let edit_state = if self.history.borrow_mut().undo(&mut changes) {
Some((EditCommandId::Undo, changes))
} else {
None
};
self.transition = Self::animate_edit(&response.ctx, response.id, edit_state);
}
if response.ctx.input_mut(|i| {
i.consume_shortcut(&egui::KeyboardShortcut::new(Modifiers::CTRL, egui::Key::Y))
Expand All @@ -670,7 +676,13 @@ impl Stave {
egui::Key::Z,
))
}) {
self.history.borrow_mut().redo(&mut vec![]); // TODO (implement) changes highlighting
let mut changes = vec![];
let edit_state = if self.history.borrow_mut().redo(&mut changes) {
Some((EditCommandId::Redo, changes))
} else {
None
};
self.transition = Self::animate_edit(&response.ctx, response.id, edit_state);
}

// Bookmarks & time navigation
Expand Down Expand Up @@ -729,30 +741,40 @@ impl Stave {
None
}

fn do_edit_command<Action: FnOnce(&Stave, &Track) -> Option<AppliedCommand>>(
&mut self,
fn animate_edit(
context: &Context,
transition_id: egui::Id,
action: Action,
) {
if let Some((command_id, changes)) = self
.history
.borrow_mut()
.update_track(|track| action(&self, track))
{
edit_state: Option<(EditCommandId, EventActionsList)>,
) -> Option<EditTransition> {
if let Some((command_id, changes)) = edit_state {
let mut changeset = Changeset::empty();
changeset.add_all(&changes);
self.transition = Some(EditTransition::start(
Some(EditTransition::start(
context,
transition_id,
command_id,
changeset,
));
))
} else {
self.transition = None;
None
}
}

fn do_edit_command<Action: FnOnce(&Stave, &Track) -> Option<AppliedCommand>>(
&mut self,
context: &Context,
transition_id: egui::Id,
action: Action,
) {
self.transition = Self::animate_edit(
context,
transition_id,
self.history
.borrow_mut()
.update_track(|track| action(&self, track)),
)
}

fn max_time(&self) -> Time {
self.history.borrow().with_track(|track| track.max_time())
}
Expand Down
2 changes: 2 additions & 0 deletions src/track_edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub enum EditCommandId {
NotesStretch,
NotesTranspose,
NotesAccent,
Undo,
Redo,
Load,
}

Expand Down
9 changes: 6 additions & 3 deletions src/track_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,19 @@ impl TrackHistory {
}

/// Maybe undo last edit action.
pub fn undo(&mut self, changes: &mut EventActionsList) {
pub fn undo(&mut self, changes: &mut EventActionsList) -> bool {
let prev_version_id = self.version - 1;
if TrackHistory::is_valid_version_id(prev_version_id) {
assert!(self.go_to_version(prev_version_id, changes));
true
} else {
false
}
}

/// Maybe redo next edit action.
pub fn redo(&mut self, changes: &mut EventActionsList) {
self.go_to_version(self.version + 1, changes);
pub fn redo(&mut self, changes: &mut EventActionsList) -> bool {
self.go_to_version(self.version + 1, changes)
}

fn discard_tail(&mut self, max_version: VersionId) {
Expand Down

0 comments on commit 8f8d426

Please sign in to comment.