Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 98 additions & 5 deletions TuneLab/UI/MainWindow/Editor/FunctionBar/FunctionBar.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using Avalonia.Controls;
using Avalonia.Media;
using DynamicData;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using TuneLab.Audio;
Expand All @@ -27,9 +30,12 @@ internal class FunctionBar : LayerPanel

public INotifiableProperty<PlayScrollTarget> PlayScrollTarget => mDependency.PlayScrollTarget;
public IActionEvent<QuantizationBase, QuantizationDivision> QuantizationChanged => mQuantizationChanged;
public IProvider<IProject> ProjectProvider => mDependency.ProjectProvider;
public IProject? Project => ProjectProvider.Object;

public interface IDependency
{
IProvider<IProject> ProjectProvider { get; }
INotifiableProperty<PianoTool> PianoTool { get; }
INotifiableProperty<PlayScrollTarget> PlayScrollTarget { get; }
}
Expand All @@ -46,21 +52,32 @@ public FunctionBar(IDependency dependency)
{
var hoverBack = Colors.White.Opacity(0.05);

void SetupToolTip(Control toggleButton,string ToolTipText)
var collapseTextItem = new TextItem() { Text = "Hide Properties".Tr(this) };
var collapseButton = new Toggle() { Width = 120, Height = 36 };
collapseButton
.AddContent(new() { Item = new BorderItem() { CornerRadius = 4 }, ColorSet = new() { Color = Style.ITEM } })
.AddContent(new() { Item = collapseTextItem, ColorSet = new() { Color = Style.LIGHT_WHITE } });
collapseButton.IsChecked = true;
collapseButton.Switched.Subscribe(() => { collapseTextItem.Text = collapseButton.IsChecked ? "Hide Properties".Tr(this) : "Show Properties".Tr(this); CollapsePropertiesAsked?.Invoke(collapseButton.IsChecked); });
dockPanel.AddDock(collapseButton, Dock.Right);

dockPanel.AddDock(new Border() { Width = 240, Background = Brushes.Transparent, IsHitTestVisible = false }, Dock.Right);

void SetupToolTip(Control toggleButton, string ToolTipText)
{
toggleButton.SetupToolTip(ToolTipText, PlacementMode.Top, verticalOffset: -8);
}

var audioControlPanel = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal, Spacing = 12, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Margin = new(12, 0) };
var audioControlPanel = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal, Spacing = 12, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Margin = new(0, 0) };
{
var playButtonIconItem = new IconItem() { Icon = Assets.Play };
var playButton = new Toggle() { Width = 36, Height = 36 }
.AddContent(new() { Item = new BorderItem() { CornerRadius = 4 }, CheckedColorSet = new() { HoveredColor = hoverBack, PressedColor = hoverBack }, UncheckedColorSet = new() { HoveredColor = hoverBack, PressedColor = hoverBack } })
.AddContent(new() { Item = playButtonIconItem, CheckedColorSet = new() { Color = Colors.White }, UncheckedColorSet = new() { Color = Style.LIGHT_WHITE.Opacity(0.5) } });

SetupToolTip(playButton, "Play".Tr(this));
playButton.Switched.Subscribe(() => { if (playButton.IsChecked) AudioEngine.Play(); else AudioEngine.Pause(); SetupToolTip(playButton, AudioEngine.IsPlaying ? "Pause".Tr(this) : "Play".Tr(this)); });
AudioEngine.PlayStateChanged += () => { playButtonIconItem.Icon = AudioEngine.IsPlaying ? Assets.Pause : Assets.Play; playButton.Display(AudioEngine.IsPlaying); SetupToolTip(playButton, AudioEngine.IsPlaying ? "Pause".Tr(this) : "Play".Tr(this));};
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 AutoPageButton(mDependency.PlayScrollTarget) { Width = 36, Height = 36 };
Expand All @@ -84,12 +101,88 @@ void SetupToolTip(Control toggleButton,string ToolTipText)
}
dockPanel.AddDock(audioControlPanel, Dock.Left);

var trackProgressTimePanel = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Margin = new(12, 0), Width = 110 };
{
var trackProgressTimeLabel_1 = new TextBlock() { Text = "0:00:00", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, FontSize = 20, Foreground = Style.TEXT_LIGHT.ToBrush(), FontFamily = "Consolas", FontWeight = FontWeight.Bold };
trackProgressTimePanel.Children.Add(trackProgressTimeLabel_1);
var trackProgressTimeLabel_2 = new TextBlock() { Text = ":000", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, FontSize = 14, Foreground = Style.TEXT_LIGHT.ToBrush(), Margin = new(-1, 2, 0, 0), FontFamily = "Consolas" };
trackProgressTimePanel.Children.Add(trackProgressTimeLabel_2);

AudioEngine.ProgressChanged += () =>
{
TimeSpan currentTime = TimeSpan.FromSeconds(AudioEngine.CurrentTime);
trackProgressTimeLabel_1.Text = $"{currentTime.Hours:D1}:{currentTime.Minutes:D2}:{currentTime.Seconds:D2}";
trackProgressTimeLabel_2.Text = $":{currentTime.Milliseconds:D3}";
};
}
dockPanel.AddDock(trackProgressTimePanel, Dock.Left);

var bpmInputPanel = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Margin = new(12, 0) };
{
var bpmInput = new EditableLabel() { Width = 70, Padding = new(0), FontFamily = Assets.NotoMono, FontSize = 20, CornerRadius = new(4), HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center, Foreground = Style.LIGHT_WHITE.ToBrush(), Background = Style.BACK.ToBrush() };
bpmInput.Text = "120.00";
bpmInput.EndInput.Subscribe(() =>
{
// 查找当前时间对应的bpm和index
var bpm = Project?.TempoManager.GetBpmAt((double)(Project?.TempoManager.GetTick(AudioEngine.CurrentTime)));
var index = Project?.TempoManager.Tempos.IndexOf(Project?.TempoManager.Tempos.FirstOrDefault(x => x.Bpm == bpm));
// 设置bpm
if (index == null) return;
Project?.TempoManager.SetBpm((int)index, double.Parse(bpmInput.Text));
Project?.Commit();
});
AudioEngine.ProgressChanged += () =>
{
if (Project?.TempoManager.Tempos.Count == 0) return;
var bpm = Project?.TempoManager.GetBpmAt((double)(Project?.TempoManager.GetTick(AudioEngine.CurrentTime)));
bpmInput.Text = bpm?.ToString("f2") ?? "120.00";
};
ProjectProvider.ObjectChanged.Subscribe(() =>
{
if (Project?.TempoManager.Tempos.Count == 0) return;
var bpm = Project?.TempoManager.GetBpmAt((double)(Project?.TempoManager.GetTick(AudioEngine.CurrentTime)));
bpmInput.Text = bpm?.ToString("f2") ?? "120.00";
});
bpmInputPanel.Children.Add(bpmInput);
};
dockPanel.AddDock(bpmInputPanel, Dock.Left);

var timeSigPanel = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Margin = new(12, 0) };
{
var timeSigEdit = new EditableLabel() { Width = 30, Padding = new(0), FontFamily = Assets.NotoMono, FontSize = 20, CornerRadius = new(4), HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center, Foreground = Style.LIGHT_WHITE.ToBrush(), Background = Style.BACK.ToBrush() };
timeSigEdit.Text = Project?.TimeSignatureManager.TimeSignatures[0].Numerator.ToString() ?? "4";
timeSigEdit.EndInput.Subscribe(() =>
{
var numerator = int.Parse(timeSigEdit.Text);
var index = Project?.TimeSignatureManager.TimeSignatures.IndexOf(Project?.TimeSignatureManager.TimeSignatures.FirstOrDefault(x => x.Numerator == numerator));
if (index == null) return;
Project?.TimeSignatureManager.SetNumeratorAndDenominator((int)index, numerator, 4);
Project?.Commit();
});
AudioEngine.ProgressChanged += () =>
{
var tick = Project?.TempoManager.GetTick(AudioEngine.CurrentTime);
var timeSig = Project?.TimeSignatureManager.TimeSignatures.FirstOrDefault(x => x.BarIndex < tick);
timeSigEdit.Text = timeSig?.Numerator.ToString() ?? "4";
};
ProjectProvider.ObjectChanged.Subscribe(() =>
{
var tick = Project?.TempoManager.GetTick(AudioEngine.CurrentTime);
var timeSig = Project?.TimeSignatureManager.TimeSignatures.FirstOrDefault(x => x.BarIndex < tick);
timeSigEdit.Text = timeSig?.Numerator.ToString() ?? "4";
});
timeSigPanel.Children.Add(timeSigEdit);
var timeSigLabel = new TextBlock() { Text = "/4", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, FontSize = 20, FontWeight = FontWeight.Bold, Foreground = Style.TEXT_LIGHT.ToBrush(), FontFamily = "Consolas", Margin = new(4, 2, 0, 0) };
timeSigPanel.Children.Add(timeSigLabel);
};
dockPanel.AddDock(timeSigPanel, Dock.Left);

var quantizationPanel = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal, Spacing = 12, HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center };
{
var quantizationLabel = new TextBlock() { Text = "Quantization".Tr(this) + ": ", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center };
quantizationPanel.Children.Add(quantizationLabel);
var quantizationComboBox = new ComboBoxController() { Width = 96 };
(string option, QuantizationBase quantizationBase, QuantizationDivision quantizationDivision)[] options =
(string option, QuantizationBase quantizationBase, QuantizationDivision quantizationDivision)[] options =
[
("1/1", QuantizationBase.Base_1, QuantizationDivision.Division_1),
("1/2", QuantizationBase.Base_1, QuantizationDivision.Division_2),
Expand Down