Skip to content

Commit

Permalink
feat: 新增播放线不动,视图滚屏
Browse files Browse the repository at this point in the history
  • Loading branch information
LiuYunPlayer committed Nov 21, 2024
1 parent 65c015d commit 1b9fd28
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 43 deletions.
1 change: 1 addition & 0 deletions TuneLab/GUI/Assets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal static class Assets
public static SvgIcon CheckBoxFrame = new("<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<rect x=\"0.5\" y=\"0.5\" width=\"15\" height=\"15\" rx=\"3.5\" stroke=\"white\"/>\r\n</svg>");
public static SvgIcon Check = new("<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M3.5 9.5L6 12L12.5 5.5\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>");
public static SvgIcon AutoPage = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<rect x=\"2\" y=\"11\" width=\"16\" height=\"2\" rx=\"1\" fill=\"white\"/>\r\n<rect x=\"18\" y=\"4\" width=\"2\" height=\"16\" rx=\"1\" fill=\"white\"/>\r\n<path d=\"M17 12L13 8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"/>\r\n<path d=\"M17 12L13 16\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"/>\r\n</svg>");
public static SvgIcon AutoScroll = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<rect x=\"10\" y=\"4\" width=\"2\" height=\"16\" rx=\"1\" fill=\"white\"/>\r\n<path d=\"M16 13V18L22 12L16 6V11\" stroke=\"white\" stroke-width=\"2\" stroke-linejoin=\"round\"/>\r\n<path d=\"M9 14H3V10H9\" stroke=\"white\" stroke-width=\"2\"/>\r\n<path d=\"M13 10H15\" stroke=\"white\" stroke-width=\"2\"/>\r\n<path d=\"M13 14H15\" stroke=\"white\" stroke-width=\"2\"/>\r\n</svg>");
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>");
Expand Down
4 changes: 2 additions & 2 deletions TuneLab/GUI/Components/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ public override void Render(DrawingContext context)
var rect = this.Rect();
context.FillRectangle(Brushes.Transparent, rect);

foreach (var content in mButtonContentControllers)
foreach (var controller in mButtonContentControllers)
{
content.Content.Item.Paint(context, rect, content.Color);
controller.Content.Item.Paint(context, rect, controller.Color);
}
}

Expand Down
37 changes: 23 additions & 14 deletions TuneLab/GUI/Components/Toggle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,37 @@ internal class Toggle : Button, IDataValueController<bool>
{
public event Func<bool>? AllowSwitch;
public IActionEvent Switched => mValueChanged;
public bool IsChecked { get; private set; }

public IActionEvent ValueWillChange => mValueWillChange;
public IActionEvent ValueChanged => mValueChanged;
public IActionEvent ValueCommited => mValueCommited;
public bool Value => IsChecked;

public Toggle()
{
Pressed += () =>
public bool IsChecked
{
get => mIsChecked;
set
{
if (AllowSwitch != null && !AllowSwitch())
return;

if (IsChecked == value)
return;

mValueWillChange.Invoke();
IsChecked = !IsChecked;
mIsChecked = value;
mValueChanged.Invoke();
mValueCommited.Invoke();
foreach (var kvp in mContentMap)
{
kvp.Value.ColorSet = IsChecked ? kvp.Key.CheckedColorSet : kvp.Key.UncheckedColorSet;
}
};
CorrectColor();
}
}

public IActionEvent ValueWillChange => mValueWillChange;
public IActionEvent ValueChanged => mValueChanged;
public IActionEvent ValueCommited => mValueCommited;
public bool Value => IsChecked;

public Toggle()
{
Pressed += () => IsChecked = !IsChecked;
}

public Toggle AddContent(ToggleContent content)
Expand All @@ -54,16 +62,17 @@ public Toggle AddContent(ToggleContent content)

public void Display(bool value)
{
IsChecked = value;
mIsChecked = value;
foreach (var kvp in mContentMap)
{
kvp.Value.ColorSet = IsChecked ? kvp.Key.CheckedColorSet : kvp.Key.UncheckedColorSet;
}
CorrectColor();
}

bool mIsChecked = false;
readonly ActionEvent mValueWillChange = new();
readonly ActionEvent mValueChanged = new();
readonly ActionEvent mValueCommited = new();
Dictionary<ToggleContent, ButtonContent> mContentMap = new();
readonly Dictionary<ToggleContent, ButtonContent> mContentMap = [];
}
7 changes: 4 additions & 3 deletions TuneLab/UI/MainWindow/Editor/Editor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

namespace TuneLab.UI;

internal class Editor : DockPanel, PianoWindow.IDependency, TrackWindow.IDependency
internal class Editor : DockPanel, PianoWindow.IDependency, TrackWindow.IDependency, FunctionBar.IDependency
{
public Menu Menu { get; }
public TrackWindow TrackWindow => mTrackWindow;
Expand All @@ -50,7 +50,8 @@ internal class Editor : DockPanel, PianoWindow.IDependency, TrackWindow.IDepende
public IPlayhead Playhead => mPlayhead;
public IProvider<IProject> ProjectProvider => mDocument.ProjectProvider;
public IProvider<IPart> EditingPart => mPianoWindow.PartProvider;
public bool IsAutoPage => mFunctionBar.IsAutoPage.Value;
public INotifiableProperty<PianoTool> PianoTool { get; } = new NotifiableProperty<PianoTool>(UI.PianoTool.Note);
public INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; } = new NotifiableProperty<PlayScrollTarget>(UI.PlayScrollTarget.None);
public Editor()
{
Background = Style.BACK.ToBrush();
Expand All @@ -59,9 +60,9 @@ public Editor()

mPlayhead = new(this);

mFunctionBar = new(this);
mPianoWindow = new(this);// { VerticalAlignment = Avalonia.Layout.VerticalAlignment.Bottom };
mTrackWindow = new(this);
mFunctionBar = new(mPianoWindow);
mRightSideTabBar = new();
mRightSideBar = new() { Width = 280 };

Expand Down
61 changes: 61 additions & 0 deletions TuneLab/UI/MainWindow/Editor/FunctionBar/AutoPageButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Avalonia.Media;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TuneLab.Base.Event;
using TuneLab.GUI;
using TuneLab.GUI.Components;
using TuneLab.GUI.Input;
using TuneLab.Utils;

namespace TuneLab.UI;

internal class AutoPageButton : Toggle
{
public INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; }

public AutoPageButton(INotifiableProperty<PlayScrollTarget> playScrollTarget)
{
PlayScrollTarget = playScrollTarget;
var backContent = new ToggleContent() { Item = new BorderItem() { CornerRadius = 4 }, CheckedColorSet = new() { Color = Style.HIGH_LIGHT }, UncheckedColorSet = new() { HoveredColor = Colors.White.Opacity(0.05), PressedColor = Colors.White.Opacity(0.05) } };
var iconContent = new ToggleContent() { Item = mIconItem, CheckedColorSet = new() { Color = Colors.White }, UncheckedColorSet = new() { Color = Style.LIGHT_WHITE.Opacity(0.5) } };

AddContent(backContent);
AddContent(iconContent);
}

protected override void OnMouseDown(MouseDownEventArgs e)
{
switch (e.MouseButtonType)
{
case MouseButtonType.PrimaryButton:
PlayScrollTarget.Value = PlayScrollTarget.Value == UI.PlayScrollTarget.View ? UI.PlayScrollTarget.None : UI.PlayScrollTarget.View;
mIconItem.Icon = Assets.AutoPage;
break;
case MouseButtonType.SecondaryButton:
PlayScrollTarget.Value = PlayScrollTarget.Value == UI.PlayScrollTarget.Playhead ? UI.PlayScrollTarget.None : UI.PlayScrollTarget.Playhead;
mIconItem.Icon = Assets.AutoScroll;
break;
}

switch (PlayScrollTarget.Value)
{
case UI.PlayScrollTarget.None:

break;
case UI.PlayScrollTarget.View:

break;
case UI.PlayScrollTarget.Playhead:

break;
}

IsChecked = PlayScrollTarget.Value != UI.PlayScrollTarget.None;
InvalidateVisual();
}

readonly IconItem mIconItem = new IconItem() { Icon = Assets.AutoPage };
}
10 changes: 4 additions & 6 deletions TuneLab/UI/MainWindow/Editor/FunctionBar/FunctionBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ namespace TuneLab.UI;
internal class FunctionBar : LayerPanel
{
public event Action<double>? Moved;
public INotifiableProperty<bool> IsAutoPage { get; } = new NotifiableProperty<bool>(false);

public INotifiableProperty<PlayScrollTarget> PlayScrollTarget => mDependency.PlayScrollTarget;
public IActionEvent<QuantizationBase, QuantizationDivision> QuantizationChanged => mQuantizationChanged;

public interface IDependency
{
public INotifiableProperty<PianoTool> PianoTool { get; }
public INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; }
}

public FunctionBar(IDependency dependency)
Expand All @@ -42,7 +43,7 @@ public FunctionBar(IDependency dependency)
{
var hoverBack = Colors.White.Opacity(0.05);

void SetupToolTip(Toggle toggleButton,string ToolTipText)
void SetupToolTip(Control toggleButton,string ToolTipText)
{
ToolTip.SetPlacement(toggleButton, PlacementMode.Top);
ToolTip.SetVerticalOffset(toggleButton, -8);
Expand All @@ -62,12 +63,9 @@ void SetupToolTip(Toggle toggleButton,string ToolTipText)
AudioEngine.PlayStateChanged += () => { playButtonIconItem.Icon = AudioEngine.IsPlaying ? Assets.Pause : Assets.Play; playButton.Display(AudioEngine.IsPlaying); SetupToolTip(playButton, AudioEngine.IsPlaying ? "Pause".Tr(this) : "Play".Tr(this));};
audioControlPanel.Children.Add(playButton);

var autoPageButton = new Toggle() { Width = 36, Height = 36 }
.AddContent(new() { Item = new BorderItem() { CornerRadius = 4 }, CheckedColorSet = new() { Color = Style.HIGH_LIGHT }, UncheckedColorSet = new() { HoveredColor = hoverBack, PressedColor = hoverBack } })
.AddContent(new() { Item = new IconItem() { Icon = Assets.AutoPage }, CheckedColorSet = new() { Color = Colors.White }, UncheckedColorSet = new() { Color = Style.LIGHT_WHITE.Opacity(0.5) } });
var autoPageButton = new AutoPageButton(mDependency.PlayScrollTarget) { Width = 36, Height = 36 };

SetupToolTip(autoPageButton, "Auto Scroll".Tr(this));
autoPageButton.Bind(IsAutoPage);
audioControlPanel.Children.Add(autoPageButton);
}
dockPanel.AddDock(audioControlPanel, Dock.Left);
Expand Down
14 changes: 14 additions & 0 deletions TuneLab/UI/MainWindow/Editor/FunctionBar/PlayScrollTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TuneLab.UI;

internal enum PlayScrollTarget
{
None,
View,
Playhead,
}
9 changes: 5 additions & 4 deletions TuneLab/UI/MainWindow/Editor/PianoWindow/PianoWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

namespace TuneLab.UI;

internal class PianoWindow : DockPanel, PianoRoll.IDependency, PianoScrollView.IDependency, TimelineView.IDependency, ParameterTabBar.IDependency, AutomationRenderer.IDependency, PlayheadLayer.IDependency, FunctionBar.IDependency
internal class PianoWindow : DockPanel, PianoRoll.IDependency, PianoScrollView.IDependency, TimelineView.IDependency, ParameterTabBar.IDependency, AutomationRenderer.IDependency, PlayheadLayer.IDependency
{
public event Action? ActiveAutomationChanged;
public event Action? VisibleAutomationChanged;
Expand All @@ -35,8 +35,8 @@ public IMidiPart? Part
public PianoScrollView PianoScrollView => mPianoScrollView;
public IQuantization Quantization => mQuantization;
public IPlayhead Playhead => mDependency.Playhead;
public INotifiableProperty<PianoTool> PianoTool { get; } = new NotifiableProperty<PianoTool>(UI.PianoTool.Note);
public bool IsAutoPage => mDependency.IsAutoPage;
public INotifiableProperty<PianoTool> PianoTool => mDependency.PianoTool;
public INotifiableProperty<PlayScrollTarget> PlayScrollTarget => mDependency.PlayScrollTarget;
public string? ActiveAutomation
{
get
Expand Down Expand Up @@ -65,7 +65,8 @@ public string? ActiveAutomation
public interface IDependency
{
IPlayhead Playhead { get; }
bool IsAutoPage { get; }
INotifiableProperty<PianoTool> PianoTool { get; }
INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; }
}

public PianoWindow(IDependency dependency)
Expand Down
34 changes: 22 additions & 12 deletions TuneLab/UI/MainWindow/Editor/TimelineView/TimelineView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface IDependency
IQuantization Quantization { get; }
IProvider<ITimeline> TimelineProvider { get; }
IPlayhead Playhead { get; }
bool IsAutoPage { get; }
INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; }
}

public TimelineView(IDependency dependency)
Expand Down Expand Up @@ -52,32 +52,41 @@ public TimelineView(IDependency dependency)

TickAxis.AxisChanged += InvalidateArrange;

mDependency.PlayScrollTarget.Modified.Subscribe(() => mFixedPlayheadX = TickAxis.Tick2X(Playhead.Pos));
mDependency.TimelineProvider.ObjectChanged.Subscribe(OnTickAxisChanged, s);
mDependency.Playhead.PosChanged.Subscribe(() =>
{
if (AudioEngine.IsPlaying)
{
if (!mDependency.IsAutoPage)
if (mDependency.PlayScrollTarget.Value == PlayScrollTarget.None)
return;

if (Timeline == null)
return;

if (TickAxis.IsMoveAnimating)
return;

const double autoPageTime = 500;
var minVisibeTime = Timeline.TempoManager.GetTime(TickAxis.MinVisibleTick);
var maxVisibeTime = Timeline.TempoManager.GetTime(TickAxis.MaxVisibleTick);

var time = Timeline.TempoManager.GetTime(Playhead.Pos);
if (time + autoPageTime / 1000 >= maxVisibeTime)
if (mDependency.PlayScrollTarget.Value == PlayScrollTarget.View)
{
TickAxis.AnimateMoveTickToX(TickAxis.MaxVisibleTick, 0, autoPageTime, mPageCurve);
if (TickAxis.IsMoveAnimating)
return;

const double autoPageTime = 500;
var minVisibeTime = Timeline.TempoManager.GetTime(TickAxis.MinVisibleTick);
var maxVisibeTime = Timeline.TempoManager.GetTime(TickAxis.MaxVisibleTick);

var time = Timeline.TempoManager.GetTime(Playhead.Pos);
if (time + autoPageTime / 1000 >= maxVisibeTime)
{
TickAxis.AnimateMoveTickToX(TickAxis.MaxVisibleTick, 0, autoPageTime, mPageCurve);
}
}
else
{
TickAxis.MoveTickToX(Playhead.Pos, mFixedPlayheadX);
}
}
else
{
mFixedPlayheadX = TickAxis.Tick2X(Playhead.Pos);
if (mState == State.Seeking)
return;

Expand Down Expand Up @@ -267,6 +276,7 @@ public double GetRatio(double timeRatio)
TickAxis TickAxis => mDependency.TickAxis;
IQuantization Quantization => mDependency.Quantization;
IPlayhead Playhead => mDependency.Playhead;
double mFixedPlayheadX;

readonly IDependency mDependency;
readonly DisposableManager s = new();
Expand Down
4 changes: 2 additions & 2 deletions TuneLab/UI/MainWindow/Editor/TrackWindow/TrackWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ internal class TrackWindow : DockPanel, TimelineView.IDependency, TrackScrollVie
public IProvider<IPart> EditingPart => mDependency.EditingPart;
public IProject? Project => ProjectProvider.Object;
public TrackScrollView TrackScrollView => mTrackScrollView;
public bool IsAutoPage => mDependency.IsAutoPage;
public INotifiableProperty<PlayScrollTarget> PlayScrollTarget => mDependency.PlayScrollTarget;

public interface IDependency
{
IProvider<IProject> ProjectProvider { get; }
IPlayhead Playhead { get; }
IProvider<IPart> EditingPart { get; }
void SwitchEditingPart(IPart? part);
bool IsAutoPage { get; }
INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; }
}

public TrackWindow(IDependency dependency)
Expand Down

0 comments on commit 1b9fd28

Please sign in to comment.