Skip to content

Commit e1ecfe3

Browse files
committed
feat: 相邻锚点连接操作
1 parent a82fc61 commit e1ecfe3

File tree

2 files changed

+88
-20
lines changed

2 files changed

+88
-20
lines changed

TuneLab/UI/MainWindow/Editor/PianoWindow/PianoScrollView/PianoScrollViewItem.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using TuneLab.Extensions.Voices;
1212
using TuneLab.Base.Utils;
1313
using Avalonia.Media;
14+
using TuneLab.GUI.Input;
1415

1516
namespace TuneLab.UI;
1617

@@ -298,6 +299,7 @@ public override void Render(DrawingContext context)
298299
class PreviewAnchorGroupItem(PianoScrollView pianoScrollView) : PianoScrollViewItem(pianoScrollView)
299300
{
300301
public required IPiecewiseCurve PiecewiseCurve { get; set; }
302+
public Action<MouseDownEventArgs, bool>? OnDown { get; set; } = null;
301303

302304
public override void Render(DrawingContext context)
303305
{

TuneLab/UI/MainWindow/Editor/PianoWindow/PianoScrollView/PianoScrollViewOperation.cs

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -348,23 +348,30 @@ bool DetectWaveformPrimaryButton()
348348
if (Part == null)
349349
break;
350350

351-
if (item is AnchorItem anchorItem)
351+
if (mPreviewPitchItem != null && mPreviewPitchItem.OnDown != null)
352352
{
353-
mAnchorMoveOperation.Down(e.Position, ctrl, anchorItem.AnchorPoint);
353+
mPreviewPitchItem.OnDown.Invoke(e, ctrl);
354354
}
355355
else
356356
{
357-
if (e.IsDoubleClick || mPreviewPitch != null)
357+
if (item is AnchorItem anchorItem)
358358
{
359-
var anchor = new AnchorPoint(TickAxis.X2Tick(e.Position.X) - Part.Pos.Value, PitchAxis.Y2Pitch(e.Position.Y) - 0.5) { IsSelected = true };
360-
Part.Pitch.InsertPoint(anchor);
361-
Part.Pitch.DeselectAllAnchors();
362-
anchor.Select();
363-
mAnchorMoveOperation.Down(e.Position, ctrl, anchor);
359+
mAnchorMoveOperation.Down(e.Position, ctrl, anchorItem.AnchorPoint);
364360
}
365361
else
366362
{
367-
mAnchorSelectOperation.Down(e.Position, ctrl);
363+
if (e.IsDoubleClick)
364+
{
365+
var anchor = new AnchorPoint(TickAxis.X2Tick(e.Position.X) - Part.Pos.Value, PitchAxis.Y2Pitch(e.Position.Y) - 0.5) { IsSelected = true };
366+
Part.Pitch.InsertPoint(anchor);
367+
Part.Pitch.DeselectAllAnchors();
368+
anchor.Select();
369+
mAnchorMoveOperation.Down(e.Position, ctrl, anchor);
370+
}
371+
else
372+
{
373+
mAnchorSelectOperation.Down(e.Position, ctrl);
374+
}
368375
}
369376
}
370377
}
@@ -893,7 +900,7 @@ protected override void OnKeyUpEvent(KeyEventArgs e)
893900

894901
protected override void UpdateItems(IItemCollection items)
895902
{
896-
mPreviewPitch = null;
903+
mPreviewPitchItem = null;
897904
if (Part == null)
898905
return;
899906

@@ -972,29 +979,88 @@ protected override void UpdateItems(IItemCollection items)
972979
if (!IsHover)
973980
break;
974981

975-
if (HoverItem() != null)
982+
var hoverItem = HoverItem();
983+
var hoverAnchor = (hoverItem as AnchorItem)?.AnchorPoint;
984+
985+
IAnchorGroup? hoverAnchorOnFirstGroup = null;
986+
IAnchorGroup? hoverAnchorOnLastGroup = null;
987+
int hoverAnchorGroupIndex = -1;
988+
for (int i = 0; i < Part.Pitch.AnchorGroups.Count; i++)
989+
{
990+
var anchorGroup = Part.Pitch.AnchorGroups[i];
991+
if (anchorGroup.IsEmpty())
992+
continue;
993+
994+
if (anchorGroup.ConstFirst() == hoverAnchor)
995+
{
996+
hoverAnchorOnFirstGroup = anchorGroup;
997+
hoverAnchorGroupIndex = i;
998+
}
999+
if (anchorGroup.ConstLast() == hoverAnchor)
1000+
{
1001+
hoverAnchorOnLastGroup = anchorGroup;
1002+
hoverAnchorGroupIndex = i;
1003+
}
1004+
1005+
if (hoverAnchorGroupIndex != -1)
1006+
break;
1007+
}
1008+
1009+
// 悬浮到非首尾锚点上,忽略预览
1010+
if (hoverAnchor != null && hoverAnchorOnFirstGroup == null && hoverAnchorOnLastGroup == null)
9761011
break;
9771012

9781013
var pos = TickAxis.X2Tick(MousePosition.X) - Part.Pos.Value;
9791014
var areaID = Part.Pitch.GetAreaID(pos);
980-
int[] previewIndex = areaID.IsInGroup ? [areaID.Index] : [areaID.LeftIndex, areaID.RightIndex];
1015+
int[] previewIndex = hoverAnchor == null ?
1016+
areaID.IsInGroup ? [areaID.Index] : [areaID.LeftIndex, areaID.RightIndex] :
1017+
[.. (hoverAnchorOnFirstGroup == null ? Array.Empty<int>() : [hoverAnchorGroupIndex - 1]), hoverAnchorGroupIndex, .. (hoverAnchorOnLastGroup == null ? Array.Empty<int>() : [hoverAnchorGroupIndex + 1])];
9811018
var previewInfo = previewIndex
9821019
.Where(index => (uint)index < Part.Pitch.AnchorGroups.Count)
9831020
.Select(index => Part.Pitch.AnchorGroups[index])
984-
.Where(anchorGroup => anchorGroup.HasSelectedItem())
1021+
.Where(anchorGroup => anchorGroup.HasSelectedItem() || anchorGroup == hoverAnchorOnFirstGroup || anchorGroup == hoverAnchorOnLastGroup)
9851022
.Select(anchorGroup => anchorGroup.GetInfo().Select(p => p.ToPoint()).ToList()).ToList();
9861023

9871024
if (previewInfo.Count == 0)
9881025
break;
9891026

990-
mPreviewPitch = new PiecewiseCurve();
991-
mPreviewPitch.Set(previewInfo);
992-
foreach (var anchorGroup in mPreviewPitch.AnchorGroups)
1027+
mPreviewPitchItem = new PreviewAnchorGroupItem(this) { PiecewiseCurve = new PiecewiseCurve() };
1028+
mPreviewPitchItem.PiecewiseCurve.Set(previewInfo);
1029+
if (hoverAnchor == null)
9931030
{
994-
anchorGroup[0].Select();
1031+
foreach (var anchorGroup in mPreviewPitchItem.PiecewiseCurve.AnchorGroups)
1032+
{
1033+
anchorGroup[0].Select();
1034+
}
1035+
mPreviewPitchItem.PiecewiseCurve.InsertPoint(hoverAnchor ?? new AnchorPoint(pos, PitchAxis.Y2Pitch(MousePosition.Y) - 0.5));
1036+
mPreviewPitchItem.OnDown += (e, ctrl) =>
1037+
{
1038+
var anchor = new AnchorPoint(TickAxis.X2Tick(e.Position.X) - Part.Pos.Value, PitchAxis.Y2Pitch(e.Position.Y) - 0.5) { IsSelected = true };
1039+
Part.Pitch.InsertPoint(anchor);
1040+
Part.Pitch.DeselectAllAnchors();
1041+
anchor.Select();
1042+
mAnchorMoveOperation.Down(e.Position, ctrl, anchor);
1043+
};
1044+
}
1045+
else
1046+
{
1047+
// 先处理向后连接的,顺序不能乱!
1048+
if (hoverAnchorOnLastGroup != null)
1049+
{
1050+
mPreviewPitchItem.PiecewiseCurve.ConnectAnchorGroup(0);
1051+
if (hoverAnchorGroupIndex + 1 < Part.Pitch.AnchorGroups.Count && Part.Pitch.AnchorGroups[hoverAnchorGroupIndex + 1].HasSelectedItem())
1052+
mPreviewPitchItem.OnDown += (_, _) => Part.Pitch.ConnectAnchorGroup(hoverAnchorGroupIndex);
1053+
}
1054+
if (hoverAnchorOnFirstGroup != null)
1055+
{
1056+
mPreviewPitchItem.PiecewiseCurve.ConnectAnchorGroup(0);
1057+
if (hoverAnchorGroupIndex - 1 >= 0 && Part.Pitch.AnchorGroups[hoverAnchorGroupIndex - 1].HasSelectedItem())
1058+
mPreviewPitchItem.OnDown += (_, _) => Part.Pitch.ConnectAnchorGroup(hoverAnchorGroupIndex - 1);
1059+
}
1060+
if (mPreviewPitchItem.OnDown != null)
1061+
mPreviewPitchItem.OnDown += (e, ctrl) => mAnchorMoveOperation.Down(e.Position, ctrl, hoverAnchor);
9951062
}
996-
mPreviewPitch.InsertPoint(new AnchorPoint(pos, PitchAxis.Y2Pitch(MousePosition.Y) - 0.5));
997-
items.Add(new PreviewAnchorGroupItem(this) { PiecewiseCurve = mPreviewPitch });
1063+
items.Add(mPreviewPitchItem);
9981064

9991065
break;
10001066
default:
@@ -2781,7 +2847,7 @@ public void Up()
27812847

27822848
readonly SelectionOperation mSelectionOperation;
27832849

2784-
IPiecewiseCurve? mPreviewPitch = null;
2850+
PreviewAnchorGroupItem? mPreviewPitchItem = null;
27852851

27862852
public enum State
27872853
{

0 commit comments

Comments
 (0)