diff --git a/OpenUtau/Controls/PianoRoll.axaml b/OpenUtau/Controls/PianoRoll.axaml index 647d22145..2ba480cb5 100644 --- a/OpenUtau/Controls/PianoRoll.axaml +++ b/OpenUtau/Controls/PianoRoll.axaml @@ -359,7 +359,7 @@ - + @@ -538,6 +538,7 @@ + + + + + @@ -626,6 +631,20 @@ + + + + + + + @@ -678,4 +697,4 @@ - + \ No newline at end of file diff --git a/OpenUtau/Controls/PianoRoll.axaml.cs b/OpenUtau/Controls/PianoRoll.axaml.cs index 2fd05db2d..76ae4049f 100644 --- a/OpenUtau/Controls/PianoRoll.axaml.cs +++ b/OpenUtau/Controls/PianoRoll.axaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -11,6 +11,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.Threading; using OpenUtau.App.ViewModels; using OpenUtau.App.Views; using OpenUtau.Core; @@ -349,9 +350,25 @@ void OnMenuSearchNote(object sender, RoutedEventArgs args) { void OnMenuDetachPianoRoll(object sender, RoutedEventArgs args) { MainWindow?.SetPianoRollAttachment(); ViewModel.RaisePropertyChanged(nameof(ViewModel.PianoRollDetached)); + // 延迟通知,等窗口切换完成后再更新,避免切换过程中触发 UI 更新导致崩溃 + Dispatcher.UIThread.Post(() => { + ViewModel.RaisePropertyChanged(nameof(ViewModel.HideMenuItemVisible)); + }); } void OnMenuHidePianoRoll(object sender, RoutedEventArgs args) { + // Reset ToggleButton checked state / 重置 ToggleButton 的 checked 状态 + // Reason / 原因: + // ToggleButton keeps IsChecked=true after click, causing darker background. + // But this close button is a one-shot action, not a state toggle. + // So we manually reset it to false immediately after click. + // Since piano roll hides instantly, users never see this momentary state change. + // + // 详细说明: + // ToggleButton 点击后会保持 IsChecked=true,导致底纹变深。 + // 但关闭按钮是一次性操作,不应该保持状态,所以手动重置为 false。 + // 因为点击后钢琴卷帘立即隐藏,用户看不到这个瞬间的状态变化。 + HidePianoRollButton.IsChecked = false; if (RootWindow.DataContext is MainWindowViewModel mwvm) { mwvm.ShowPianoRoll = false; } else { @@ -360,6 +377,24 @@ void OnMenuHidePianoRoll(object sender, RoutedEventArgs args) { } // Edit Tools + private long _lastToolbarClickTime = 0; + private const long DoubleClickThreshold = 300; // 毫秒 + + void OnToolbarPointerPressed(object sender, PointerPressedEventArgs args) { + // 双击工具栏空白处关闭钢琴卷帘(仅嵌入模式生效) + if (!args.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return; + + long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); + if (now - _lastToolbarClickTime < DoubleClickThreshold) { + // 双击 + if (RootWindow.DataContext is MainWindowViewModel mwvm) { + mwvm.ShowPianoRoll = false; + } + // 分离模式下不响应,保持和原来一模一样 + } + _lastToolbarClickTime = now; + } + private CancellationTokenSource? _longPressCts; private async void OnToolButtonPointerPressed(object? sender, PointerPressedEventArgs args) { if (!args.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return; @@ -2017,4 +2052,4 @@ public void OnNext(UCommand cmd, bool isUndo) { } } } -} +} \ No newline at end of file diff --git a/OpenUtau/ViewModels/PianoRollViewModel.cs b/OpenUtau/ViewModels/PianoRollViewModel.cs index f4f1bfbcb..14120b084 100644 --- a/OpenUtau/ViewModels/PianoRollViewModel.cs +++ b/OpenUtau/ViewModels/PianoRollViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reactive; @@ -68,6 +68,7 @@ public class PianoRollViewModel : ViewModelBase, ICmdSubscriber { public bool PlaybackAutoScroll1 { get => Preferences.Default.PlaybackAutoScroll == 1 ? true : false; } public bool PlaybackAutoScroll2 { get => Preferences.Default.PlaybackAutoScroll == 2 ? true : false; } public bool PianoRollDetached { get => Preferences.Default.DetachPianoRoll; } + public bool HideMenuItemVisible => !Preferences.Default.DetachPianoRoll; public bool ShowPhonemizerTags { get => Preferences.Default.ShowPhonemizerTags; set { @@ -319,4 +320,4 @@ public void OnNext(UCommand cmd, bool isUndo) { #endregion } -} +} \ No newline at end of file