Skip to content

Commit

Permalink
锚点选择
Browse files Browse the repository at this point in the history
  • Loading branch information
LiuYunPlayer committed Jun 25, 2024
1 parent e71cf20 commit 3ff1903
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 15 deletions.
1 change: 1 addition & 0 deletions TuneLab/GUI/Assets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ internal static class Assets
public static SvgIcon Play = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<g clip-path=\"url(#clip0_249_127)\">\r\n<path d=\"M21 10.2679C22.3333 11.0377 22.3333 12.9623 21 13.7321L9 20.6603C7.66667 21.4301 6 20.4678 6 18.9282L6 5.0718C6 3.5322 7.66667 2.56995 9 3.33975L21 10.2679Z\" fill=\"white\"/>\r\n</g>\r\n<defs>\r\n<clipPath id=\"clip0_249_127\">\r\n<rect width=\"24\" height=\"24\" fill=\"white\"/>\r\n</clipPath>\r\n</defs>\r\n</svg>");
public static SvgIcon Select = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<rect x=\"8\" y=\"4\" width=\"8\" height=\"2\" rx=\"1\" fill=\"white\"/>\r\n<rect x=\"8\" y=\"18\" width=\"8\" height=\"2\" rx=\"1\" fill=\"white\"/>\r\n<rect x=\"11\" y=\"6\" width=\"2\" height=\"12\" fill=\"white\"/>\r\n</svg>");
public static SvgIcon Hyphen = new("<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<rect x=\"4\" y=\"7\" width=\"8\" height=\"2\" rx=\"1\" fill=\"white\"/>\r\n</svg>");
public static SvgIcon Anchor = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<circle cx=\"6\" cy=\"16\" r=\"2.5\" stroke=\"white\"/>\r\n<circle cx=\"18\" cy=\"12\" r=\"2.5\" stroke=\"white\"/>\r\n<circle cx=\"10\" cy=\"8\" r=\"2.5\" stroke=\"white\"/>\r\n<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M11.7939 8.88516C11.9259 8.61833 12 8.31783 12 8.00002C12 7.56902 11.8636 7.16987 11.6318 6.84332C12.8738 6.96097 14.0258 7.49932 14.8895 8.01753C15.5705 8.42616 16.1442 8.8654 16.5464 9.20055C16.7485 9.36892 16.9096 9.51304 17.022 9.61678C17.0783 9.6687 17.1224 9.71065 17.1536 9.74064L17.1904 9.77645L17.2013 9.78719L17.2049 9.79069L17.2061 9.79196L17.2067 9.79248C17.2069 9.7927 17.2071 9.79291 16.5 10.5C15.7929 11.2071 15.7931 11.2073 15.7932 11.2075L15.7893 11.2036L15.7663 11.1813C15.7447 11.1605 15.7108 11.1282 15.6655 11.0864C15.5747 11.0026 15.439 10.8811 15.266 10.737C14.9182 10.4471 14.4294 10.0739 13.8605 9.73251C13.1819 9.32538 12.4738 9.01369 11.7939 8.88516ZM9.12041 9.79673C8.47773 9.48151 8.02898 8.83164 8.00133 8.07428C7.09234 8.93355 6.53025 10.0844 6.18519 11.0333C5.91226 11.7838 5.74374 12.4937 5.6432 13.0132C5.59268 13.2742 5.5587 13.4904 5.5371 13.6438C5.52629 13.7206 5.51854 13.7818 5.51336 13.8253L5.50743 13.877L5.50578 13.8924L5.50526 13.8974L5.50508 13.8992L5.505 13.8999C5.50497 13.9003 5.50494 13.9005 6.49998 14.0001C7.49502 14.0996 7.49499 14.0998 7.49497 14.1001L7.49493 14.1004L7.49488 14.1009L7.49493 14.1005L7.49497 14.1001L7.49558 14.0944L7.4993 14.062C7.5029 14.0318 7.50883 13.9846 7.51755 13.9227C7.53501 13.7988 7.56353 13.6165 7.60676 13.3932C7.69373 12.9439 7.8377 12.3412 8.06477 11.7168C8.33341 10.978 8.68222 10.3057 9.12041 9.79673Z\" fill=\"white\"/>\r\n</svg>\r\n");
public static SvgIcon None = new("");

public static FontFamily NotoMono = new FontFamily("NotoMono");
Expand Down
1 change: 1 addition & 0 deletions TuneLab/Views/FunctionBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ void OnPianoToolChanged()
}
AddButton(PianoTool.Note, Assets.Pointer);
AddButton(PianoTool.Pitch, Assets.Pitch);
AddButton(PianoTool.Anchor, Assets.Anchor);
AddButton(PianoTool.Lock, Assets.Brush);
AddButton(PianoTool.Vibrato, Assets.Vibrato);
AddButton(PianoTool.Select, Assets.Select);
Expand Down
64 changes: 49 additions & 15 deletions TuneLab/Views/PianoScrollView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public PianoScrollView(IDependency dependency)
mWaveformNoteResizeOperation = new(this);
mWaveformPhonemeResizeOperation = new(this);
mSelectionOperation = new(this);
mAnchorSelectOperation = new(this);

mDependency.PartProvider.ObjectChanged.Subscribe(Update, s);
mDependency.PartProvider.When(p => p.Modified).Subscribe(Update, s);
Expand Down Expand Up @@ -307,11 +308,14 @@ protected override void OnRender(DrawingContext context)

// draw pitch
double pitchOpacity = MathUtility.LineValue(-6.7, 0, -4.3, 1, TickAxis.ScaleLevel).Limit(0, 1);
if (pitchOpacity == 0)
goto FinishDrawPitch;

Color pitchColor = mDependency.PianoTool == PianoTool.Note ? Colors.White.Opacity(pitchOpacity * 0.3) : Color.Parse(ConstantDefine.PitchColor).Opacity(pitchOpacity);

DrawSynthesizedPitch(context, pitchOpacity, pitchColor);
DrawSynthesizedPitch(context, pitchColor);

if (mDependency.PianoTool == PianoTool.Pitch || mDependency.PianoTool == PianoTool.Lock)
if (mDependency.PianoTool == PianoTool.Pitch || mDependency.PianoTool == PianoTool.Lock || mDependency.PianoTool == PianoTool.Anchor)
context.FillRectangle(Colors.Black.Opacity(0.25).ToBrush(), this.Rect());

DrawVibratos(context);
Expand All @@ -326,10 +330,11 @@ protected override void OnRender(DrawingContext context)
if (vibrato.GlobalStartPos() >= maxVisibleTick)
break;

DrawPitch(context, TickAxis.Tick2X(vibrato.GlobalStartPos()), TickAxis.Tick2X(vibrato.GlobalEndPos()), Part.Pitch.GetValues, pitchOpacity, pitchColor.Opacity(0.5), 1);
DrawPitch(context, TickAxis.Tick2X(vibrato.GlobalStartPos()), TickAxis.Tick2X(vibrato.GlobalEndPos()), Part.Pitch.GetValues, pitchColor.Opacity(0.5), 1);
}
}
DrawPitch(context, 0, Bounds.Width, Part.GetFinalPitch, pitchOpacity, pitchColor, mDependency.PianoTool == PianoTool.Note ? 1 : 2);
DrawPitch(context, 0, Bounds.Width, Part.GetFinalPitch, pitchColor, mDependency.PianoTool == PianoTool.Note ? 1 : 2);
FinishDrawPitch:

// draw select
if (mNoteSelectOperation.IsOperating)
Expand All @@ -344,6 +349,12 @@ protected override void OnRender(DrawingContext context)
context.DrawRectangle(SelectionColor.Opacity(0.25).ToBrush(), new Pen(SelectionColor.ToUInt32()), rect);
}

if (mAnchorSelectOperation.IsOperating)
{
var rect = mAnchorSelectOperation.SelectionRect();
context.DrawRectangle(SelectionColor.Opacity(0.25).ToBrush(), new Pen(SelectionColor.ToUInt32()), rect);
}

double start = TickAxis.Tick2X(Part.StartPos);
if (start > 0)
{
Expand All @@ -367,11 +378,8 @@ protected override void OnRender(DrawingContext context)
DrawWaveform(context);
}

void DrawSynthesizedPitch(DrawingContext context, double pitchOpacity, Color pitchColor)
void DrawSynthesizedPitch(DrawingContext context, Color pitchColor)
{
if (pitchOpacity == 0)
return;

if (Part == null)
return;

Expand All @@ -382,9 +390,6 @@ void DrawSynthesizedPitch(DrawingContext context, double pitchOpacity, Color pit

foreach (var piece in Part.SynthesisPieces)
{
if (pitchOpacity == 0)
continue;

var result = piece.SynthesisResult;
if (result == null)
continue;
Expand Down Expand Up @@ -426,11 +431,8 @@ void DrawSynthesizedPitch(DrawingContext context, double pitchOpacity, Color pit
}
}

void DrawPitch(DrawingContext context, double left, double right, Func<IReadOnlyList<double>, double[]> getPitch, double pitchOpacity, Color pitchColor, double thickness)
void DrawPitch(DrawingContext context, double left, double right, Func<IReadOnlyList<double>, double[]> getPitch, Color pitchColor, double thickness)
{
if (pitchOpacity == 0)
return;

if (Part == null)
return;

Expand Down Expand Up @@ -461,10 +463,42 @@ void DrawPitch(DrawingContext context, double left, double right, Func<IReadOnly
if (pitchLine.Count != 0)
pitchLines.Add(pitchLine);

var start = TickAxis.X2Tick(left) - pos;
var end = TickAxis.X2Tick(right) - pos;
foreach (var pitchPoints in pitchLines)
{
context.DrawCurve(pitchPoints, pitchColor, thickness);
}

if (mDependency.PianoTool != PianoTool.Anchor)
return;

IBrush pointBrush = pitchColor.ToBrush();
IPen pointPen = new Pen(pointBrush);
foreach (var anchorLine in Part.Pitch.AnchorLines)
{
if (anchorLine.End <= start)
continue;

if (anchorLine.Start >= end)
break;

foreach (var anchor in anchorLine)
{
if (anchor.Pos < start)
continue;

if (anchor.Pos > end)
break;

var center = new Point(TickAxis.Tick2X(pos + anchor.Pos), PitchAxis.Pitch2Y(anchor.Value + 0.5));
context.DrawEllipse(pointBrush, null, center, 2, 2);
if (!anchor.IsSelected)
continue;

context.DrawEllipse(null, pointPen, center, 5.5, 5.5);
}
}
}

void DrawVibratos(DrawingContext context)
Expand Down
18 changes: 18 additions & 0 deletions TuneLab/Views/PianoScrollViewItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,24 @@ public override bool Raycast(Point point)
}
}

class AnchorItem(PianoScrollView pianoScrollView) : PianoScrollViewItem(pianoScrollView)
{
public required AnchorPoint AnchorPoint { get; set; }

public Point Position()
{
if (PianoScrollView.Part == null)
return new Point();

return new Point(PianoScrollView.TickAxis.Tick2X(PianoScrollView.Part.Pos + AnchorPoint.Pos), PianoScrollView.PitchAxis.Pitch2Y(AnchorPoint.Value + 0.5));
}

public override bool Raycast(Point point)
{
return Point.Distance(Position(), point) <= 6;
}
}

class WaveformBackItem(PianoScrollView pianoScrollView) : PianoScrollViewItem(pianoScrollView)
{
public override bool Raycast(Point point)
Expand Down
75 changes: 75 additions & 0 deletions TuneLab/Views/PianoScrollViewOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,26 @@ bool DetectWaveformPrimaryButton()
break;
}
break;
case PianoTool.Anchor:
switch (e.MouseButtonType)
{
case MouseButtonType.PrimaryButton:
if (!DetectWaveformPrimaryButton())
{
if (item is AnchorItem anchorItem)
{

}
else
{
mAnchorSelectOperation.Down(e.Position, ctrl);
}
}
break;
case MouseButtonType.SecondaryButton:
break;
}
break;
case PianoTool.Lock:
switch (e.MouseButtonType)
{
Expand Down Expand Up @@ -555,6 +575,9 @@ protected override void OnMouseRelativeMoveToView(MouseMoveEventArgs e)
Cursor = new Cursor(StandardCursorType.Ibeam);
mSelectionOperation.Move(e.Position.X, alt);
break;
case State.AnchorSelecting:
mAnchorSelectOperation.Move(e.Position);
break;
default:
var item = ItemAt(e.Position);
if (item is WaveformNoteResizeItem || item is WaveformPhonemeResizeItem)
Expand Down Expand Up @@ -694,6 +717,10 @@ protected override void OnMouseUp(MouseUpEventArgs e)
if (e.MouseButtonType == MouseButtonType.PrimaryButton)
mSelectionOperation.Up();
break;
case State.AnchorSelecting:
if (e.MouseButtonType == MouseButtonType.PrimaryButton)
mAnchorSelectOperation.Up();
break;
default:
break;
}
Expand Down Expand Up @@ -838,6 +865,7 @@ protected override void UpdateItems(IItemCollection items)
var tempoManager = Part.TempoManager;
var viewStartTime = tempoManager.GetTime(startPos);
var viewEndTime = tempoManager.GetTime(endPos);
double partPos = Part.Pos;

switch (mDependency.PianoTool)
{
Expand Down Expand Up @@ -881,6 +909,27 @@ protected override void UpdateItems(IItemCollection items)
items.Add(new VibratoReleaseItem(this) { Vibrato = vibrato });
}
break;
case PianoTool.Anchor:
foreach (var anchorLine in Part.Pitch.AnchorLines)
{
if (partPos + anchorLine.End < startPos)
continue;

if (partPos + anchorLine.Start > endPos)
break;

foreach (var anchor in anchorLine)
{
if (partPos + anchor.Pos < startPos)
continue;

if (partPos + anchor.Pos > endPos)
break;

items.Add(new AnchorItem(this) { AnchorPoint = anchor });
}
}
break;
default:
break;
}
Expand Down Expand Up @@ -2257,6 +2306,31 @@ public void Up()

IVibratoItem? mOperatingVibratoItem = null;

class AnchorSelectOperation(PianoScrollView pianoScrollView) : SelectOperation<AnchorPoint>(pianoScrollView)
{
protected override State SelectState => State.AnchorSelecting;

protected override IEnumerable<AnchorPoint>? Collection => PianoScrollView.Part?.Pitch.AnchorLines.SelectMany(anchorLine => anchorLine);

protected override void Select(IEnumerable<AnchorPoint> items, double minTick, double maxTick, double minPitch, double maxPitch)
{
foreach (var item in items)
{
if (item.Pos < minTick)
continue;

if (item.Pos > maxTick)
break;

var pitch = item.Value + 0.5;
if (pitch >= minPitch && pitch <= maxPitch)
item.Select();
}
}
}

readonly AnchorSelectOperation mAnchorSelectOperation;

class WaveformNoteResizeOperation(PianoScrollView pianoScrollView) : Operation(pianoScrollView)
{
public void Down(double x, INote? left, INote? right)
Expand Down Expand Up @@ -2505,6 +2579,7 @@ public enum State
WaveformNoteResizing,
WaveformPhonemeResizing,
SelectionCreating,
AnchorSelecting,
}

State mState = State.None;
Expand Down
1 change: 1 addition & 0 deletions TuneLab/Views/PianoTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ internal enum PianoTool
{
Note,
Pitch,
Anchor,
Lock,
Vibrato,
Select,
Expand Down

0 comments on commit 3ff1903

Please sign in to comment.