Skip to content

Commit

Permalink
Merge pull request #900 from yqzhishen/resize-from-start
Browse files Browse the repository at this point in the history
Support resizing notes from their heads
  • Loading branch information
stakira authored Nov 14, 2023
2 parents c287eca + 85cfaf4 commit ca7b9ca
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 20 deletions.
16 changes: 11 additions & 5 deletions OpenUtau/ViewModels/NotesViewModelHitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public struct NoteHitInfo {
public UPhoneme phoneme;
public bool hitBody;
public bool hitResizeArea;
public bool hitResizeAreaFromStart;
public bool hitX;
}

Expand Down Expand Up @@ -72,12 +73,17 @@ public NoteHitInfo HitTestNote(Point point) {
result.note = note;
result.hitX = true;
var tone = viewModel.PointToTone(point);
if (tone == note.tone) {
result.hitBody = true;
double x = viewModel.TickToneToPoint(note.End, tone).X;
result.hitResizeArea = point.X <= x && point.X > x - ViewConstants.ResizeMargin;
break;
if (tone != note.tone) {
continue;
}
result.hitBody = true;
double x1 = viewModel.TickToneToPoint(note.position, note.tone).X;
double x2 = viewModel.TickToneToPoint(note.End, tone).X;
var hitLeftResizeArea = point.X >= x1 && point.X < x1 + ViewConstants.ResizeMargin;
var hitRightResizeArea = point.X <= x2 && point.X > x2 - ViewConstants.ResizeMargin;
result.hitResizeAreaFromStart = hitLeftResizeArea && !hitRightResizeArea; // prefer resizing from end
result.hitResizeArea = hitLeftResizeArea || hitRightResizeArea; // hit either of the areas
break;
}
return result;
}
Expand Down
54 changes: 40 additions & 14 deletions OpenUtau/Views/NoteEditStates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,22 +279,35 @@ public override void End(IPointer pointer, Point point) {

class NoteResizeEditState : NoteEditState {
public readonly UNote note;
public readonly UNote? nextNote;
public readonly bool resizeNext;
public readonly UNote? neighborNote;
public readonly bool resizeNeighbor;
public readonly bool fromStart;
public NoteResizeEditState(
Control control,
PianoRollViewModel vm,
IValueTip valueTip,
UNote note,
bool resizeNext) : base(control, vm, valueTip) {
bool resizeNeighbor,
bool fromStart = false) : base(control, vm, valueTip) {
this.note = note;
var notesVm = vm.NotesViewModel;
if (!notesVm.Selection.Contains(note)) {
notesVm.DeselectNotes();
}
this.resizeNext = notesVm.Selection.Count == 0 &&
resizeNext && note.Next != null && note.End == note.Next.position;
nextNote = note.Next;
if (fromStart) {
this.resizeNeighbor = notesVm.Selection.Count == 0
&& resizeNeighbor
&& note.Prev != null
&& note.position == note.Prev.End;
neighborNote = note.Prev;
} else {
this.resizeNeighbor = notesVm.Selection.Count == 0
&& resizeNeighbor
&& note.Next != null
&& note.End == note.Next.position;
neighborNote = note.Next;
}
this.fromStart = fromStart;
}
public override void Update(IPointer pointer, Point point) {
var project = DocManager.Inst.Project;
Expand All @@ -304,11 +317,16 @@ public override void Update(IPointer pointer, Point point) {
return;
}
int snapUnit = project.resolution * 4 / notesVm.SnapDiv;
int newEnd = notesVm.PointToTick(point);
int newTick = notesVm.PointToTick(point);
if (notesVm.IsSnapOn) {
newEnd = (int)Math.Floor((double)newEnd / snapUnit) * snapUnit + snapUnit;
newTick = this.fromStart
? (int)Math.Floor((double)newTick / snapUnit) * snapUnit
: (int)Math.Floor((double)newTick / snapUnit) * snapUnit + snapUnit;
}
int deltaDuration = newEnd - note.End;

int deltaDuration = this.fromStart
? note.position - newTick
: newTick - note.End;
int minNoteTicks = notesVm.IsSnapOn ? snapUnit : 15;
if (deltaDuration < 0) {
int maxNegDelta = note.duration - minNoteTicks;
Expand All @@ -320,23 +338,31 @@ public override void Update(IPointer pointer, Point point) {
}
deltaDuration = Math.Max(deltaDuration, -maxNegDelta);
}
if (resizeNext && nextNote != null) {
var maxDelta = Math.Max(0, nextNote.duration - minNoteTicks);
if (resizeNeighbor && neighborNote != null) {
var maxDelta = Math.Max(0, neighborNote.duration - minNoteTicks);
deltaDuration = Math.Min(deltaDuration, maxDelta);
}
if (deltaDuration == 0) {
valueTip.UpdateValueTip(note.duration.ToString());
return;
}
if (notesVm.Selection.Count == 0) {
if (resizeNext && nextNote != null) {
DocManager.Inst.ExecuteCmd(new MoveNoteCommand(part, nextNote, deltaDuration, 0));
DocManager.Inst.ExecuteCmd(new ResizeNoteCommand(part, nextNote, -deltaDuration));
if (resizeNeighbor && neighborNote != null) {
if (!fromStart) {
DocManager.Inst.ExecuteCmd(new MoveNoteCommand(part, neighborNote, deltaDuration, 0));
}
DocManager.Inst.ExecuteCmd(new ResizeNoteCommand(part, neighborNote, -deltaDuration));
}
if (fromStart) {
DocManager.Inst.ExecuteCmd(new MoveNoteCommand(part, note, -deltaDuration, 0));
}
DocManager.Inst.ExecuteCmd(new ResizeNoteCommand(part, note, deltaDuration));
valueTip.UpdateValueTip(note.duration.ToString());
return;
}
if (fromStart) {
DocManager.Inst.ExecuteCmd(new MoveNoteCommand(part, notesVm.Selection.ToList(), -deltaDuration, 0));
}
DocManager.Inst.ExecuteCmd(new ResizeNoteCommand(part, notesVm.Selection.ToList(), deltaDuration));
valueTip.UpdateValueTip(note.duration.ToString());
}
Expand Down
3 changes: 2 additions & 1 deletion OpenUtau/Views/PianoRollWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ private void NotesCanvasLeftPointerPressed(Control control, PointerPoint point,
if (noteHitInfo.hitResizeArea) {
editState = new NoteResizeEditState(
control, ViewModel, this, noteHitInfo.note,
args.KeyModifiers == KeyModifiers.Alt);
args.KeyModifiers == KeyModifiers.Alt,
fromStart: noteHitInfo.hitResizeAreaFromStart);
Cursor = ViewConstants.cursorSizeWE;
} else if (args.KeyModifiers == cmdKey) {
ViewModel.NotesViewModel.ToggleSelectNote(noteHitInfo.note);
Expand Down

0 comments on commit ca7b9ca

Please sign in to comment.