diff --git a/GUI/MainWindow.xaml b/GUI/MainWindow.xaml index b3b24bff..a81c422d 100644 --- a/GUI/MainWindow.xaml +++ b/GUI/MainWindow.xaml @@ -109,6 +109,23 @@ + + + + + + @@ -255,10 +272,74 @@ + + + + + + + + + + + @@ -424,5 +505,13 @@ + + + + + + + + diff --git a/GUI/MainWindow.xaml.cs b/GUI/MainWindow.xaml.cs index 868e7050..235a8456 100644 --- a/GUI/MainWindow.xaml.cs +++ b/GUI/MainWindow.xaml.cs @@ -45,6 +45,12 @@ using Rnd.Windows; using Microsoft.Win32; using NAudio.Wave; +#region ADL +using Hardcodet.Wpf.TaskbarNotification; +using System.Drawing; +using Form = System.Windows.Forms; +#endregion + namespace GARbro.GUI { /// @@ -58,8 +64,48 @@ namespace GARbro.GUI const StringComparison StringIgnoreCase = StringComparison.CurrentCultureIgnoreCase; + #region ADL + + Icon app_icon = new Icon(Application.GetResourceStream(new Uri("pack://application:,,,/images/sample.ico")).Stream); + TaskbarIcon tray = new TaskbarIcon(); + Form.Timer hide_timer = null; + private int counter = 0; + private void hide_timer_Tick(object sender, EventArgs e) + { + counter--; + if (counter == 0) + { + hide_timer.Stop(); + tray.HideBalloonTip(); + } + } + /// + /// Show a balloon tip in tray icon by given timeout. + /// + /// in seconds + /// + /// + private void trayShowBalloonTip(int timeout, string title, string message) + { + if (timeout > 0) + counter = timeout; + tray.ShowBalloonTip(title, message, app_icon, true); + hide_timer = new Form.Timer(); + hide_timer.Interval = 1000; //milliseconds + hide_timer.Tick += hide_timer_Tick; + hide_timer.Start(); + } + + private void trayUpdate(string msg) + { + tray.ToolTipText = msg; + } + +#endregion public MainWindow() { + + m_app = Application.Current as App; InitializeComponent(); if (this.Top < 0) this.Top = 0; @@ -83,6 +129,51 @@ namespace GARbro.GUI } }; pathLine.EnterKeyDown += acb_OnKeyDown; + +#region ADL + var ico = new Icon(Application.GetResourceStream(new Uri("pack://application:,,,/images/sample.ico")).Stream); + tray.Icon = app_icon; + tray.ToolTipText = guiStrings.MsgRunning; + // Init member + + { + m_whiterect = new System.Windows.Shapes.Rectangle(); + m_whiterect.Stretch = System.Windows.Media.Stretch.Fill; + m_whiterect.Fill = System.Windows.Media.Brushes.Black; + m_whiterect.Width = btn_appPauseControl.Width; + m_whiterect.Height = btn_appPauseControl.Width; + } + { + m_btnContinue_state_continue = new System.Windows.Shapes.Polygon(); + m_btnContinue_state_continue.Stroke = System.Windows.Media.Brushes.Black; + m_btnContinue_state_continue.Stretch = System.Windows.Media.Stretch.None; + m_btnContinue_state_continue.Fill = System.Windows.Media.Brushes.Black; + m_btnContinue_state_continue.Points.Add(new System.Windows.Point(1, 1)); + m_btnContinue_state_continue.Points.Add(new System.Windows.Point(1, 9)); + m_btnContinue_state_continue.Points.Add(new System.Windows.Point(9, 5)); + } + { + m_btnContinue_state_pause = new System.Windows.Shapes.Path(); + m_btnContinue_state_pause.Stroke = System.Windows.Media.Brushes.Black; + m_btnContinue_state_pause.StrokeThickness = 3; + System.Windows.Media.PathGeometry pathGeometry = new System.Windows.Media.PathGeometry(); + + System.Windows.Media.PathFigure line0 = new System.Windows.Media.PathFigure(); + System.Windows.Media.PathFigure line1 = new System.Windows.Media.PathFigure(); + System.Windows.Media.LineSegment segment0 = new System.Windows.Media.LineSegment(); + System.Windows.Media.LineSegment segment1 = new System.Windows.Media.LineSegment(); + line0.StartPoint = new System.Windows.Point(2.0, 0.0); + line1.StartPoint = new System.Windows.Point(8.0, 0.0); + segment0.Point = new System.Windows.Point(2.0, 8.0); + segment1.Point = new System.Windows.Point(8.0, 8.0); + line0.Segments.Add(segment0); + line1.Segments.Add(segment1); + + pathGeometry.Figures.Add(line0); + pathGeometry.Figures.Add(line1); + m_btnContinue_state_pause.Data = pathGeometry; + } +#endregion } void WindowLoaded (object sender, RoutedEventArgs e) @@ -371,7 +462,7 @@ namespace GARbro.GUI } } - #region Refresh view on filesystem changes +#region Refresh view on filesystem changes private FileSystemWatcher m_watcher = new FileSystemWatcher(); @@ -410,7 +501,7 @@ namespace GARbro.GUI Dispatcher.Invoke (RefreshView); } } - #endregion +#endregion /// /// Select specified item within CurrentDirectory and bring it into a view. @@ -755,7 +846,7 @@ namespace GARbro.GUI } } - #region Navigation history implementation +#region Navigation history implementation internal string CurrentPath { get { return ViewModel.Path.First(); } } @@ -826,7 +917,7 @@ namespace GARbro.GUI { e.CanExecute = m_history.CanRedo(); } - #endregion +#endregion private void OpenFileExec (object control, ExecutedRoutedEventArgs e) { @@ -895,7 +986,13 @@ namespace GARbro.GUI return; if ("audio" == entry.Type) { - PlayFile (entry.Source); +#region ADL + if (AudioFileList.Count() > 0) + { + AudioFileList.Clear(); + } +#endregion + PlayFile(entry.Source); return; } OpenDirectoryEntry (ViewModel, entry); @@ -978,6 +1075,160 @@ namespace GARbro.GUI } } +#region ADL_PLAYBACK + List AudioFileList = new List(); + bool isAudioLoop = false; + int CurrentAudioFileListIdx = 0; + + /* + private T[] InitArray(int count) where T : new() + { + T[] array = new T[count]; + for (int i = 0; i < count; i++) + array[i] = new T(); + return array; + } + */ + + System.Windows.Shapes.Rectangle m_whiterect = null; + System.Windows.Shapes.Polygon m_btnContinue_state_continue = null; + System.Windows.Shapes.Path m_btnContinue_state_pause = null; + + + private void SetAppPauseControlIcon() + { + btn_appPauseControl.Content = m_whiterect; + if (AudioDevice.PlaybackState == PlaybackState.Paused) + { + btn_appPauseControl.Content = m_btnContinue_state_continue; + } + else if (AudioDevice.PlaybackState == PlaybackState.Playing) + { + btn_appPauseControl.Content = m_btnContinue_state_pause; + } + } + + private void AudioPlayAllHelper(object control, ExecutedRoutedEventArgs e) + { + List rawfilelist = null; + + bool isRegionSelected = (CurrentDirectory.SelectedItems.Count > 0); + if (isRegionSelected) + { + rawfilelist = new List(CurrentDirectory.SelectedItems.Count); + foreach (var it in CurrentDirectory.SelectedItems) + { + rawfilelist.Add(((EntryViewModel)(it)).Source); + } + } + else + { + rawfilelist = VFS.GetFiles().ToList(); + } + + AudioFileList.Clear(); + AudioFileList.Capacity = rawfilelist.Count(); + CurrentAudioFileListIdx = 0; + + foreach (var entry in rawfilelist) + { + if (entry.Type == "audio") + { + AudioFileList.Add(entry); + } + } + + if (AudioFileList.Count() > 0) + { + PlayFile(AudioFileList[0]); + } + else + { + string selected = isRegionSelected ? "selected items" : "current directory"; + SetStatusText(string.Format("Files in {0} cannot be played.", selected)); + } + } + private void CanAudioNextExec(object control, CanExecuteRoutedEventArgs e) + { + e.CanExecute = (AudioFileList.Count > 1) ? true : false; + } + private void AudioNextExec(object control, ExecutedRoutedEventArgs e) + { + ++CurrentAudioFileListIdx; + if (CurrentAudioFileListIdx >= AudioFileList.Count) CurrentAudioFileListIdx = 0; + PlayFile(AudioFileList[CurrentAudioFileListIdx]); + } + private void CanAudioPreviousExec(object control, CanExecuteRoutedEventArgs e) + { + e.CanExecute = (AudioFileList.Count > 1) ? true : false; + } + private void AudioPreviousExec(object control, ExecutedRoutedEventArgs e) + { + --CurrentAudioFileListIdx; + if (CurrentAudioFileListIdx < 0) CurrentAudioFileListIdx = AudioFileList.Count - 1; + PlayFile(AudioFileList[CurrentAudioFileListIdx]); + } + private void AudioLoopAllExec(object control, ExecutedRoutedEventArgs e) + { + isAudioLoop = true; + AudioPlayAllHelper(control, e); + } + private void CanAudioLoopAllExec(object control, CanExecuteRoutedEventArgs e) + { + e.CanExecute = true; + } + private void AudioPlayAllExec(object control, ExecutedRoutedEventArgs e) + { + isAudioLoop = false; + AudioPlayAllHelper(control, e); + } + private void CanAudioPlayAllExec(object control, CanExecuteRoutedEventArgs e) + { + e.CanExecute = true; + } + private void AudioStopAllExec(object control, ExecutedRoutedEventArgs e) + { + if (AudioFileList.Count > 0) + { + AudioFileList.Clear(); + } + AudioDevice.Stop(); + } + + private void CanAudioStopAllExec(object control, CanExecuteRoutedEventArgs e) + { + isAudioLoop = false; + e.CanExecute = (AudioDevice != null && AudioDevice.PlaybackState != PlaybackState.Stopped); + } + private void AudioPauseContinueExec(object control, ExecutedRoutedEventArgs e) + { + if (AudioDevice != null) + { + if (AudioDevice.PlaybackState == PlaybackState.Paused) + { + trayUpdate(String.Format(guiStrings.MsgNowPlaying, AudioFileList[CurrentAudioFileListIdx].Name)); + AudioDevice.Play(); + } + else if (AudioDevice.PlaybackState == PlaybackState.Playing) + { + trayUpdate(String.Format(guiStrings.MsgPaused, AudioFileList[CurrentAudioFileListIdx].Name)); + AudioDevice.Pause(); + } + SetAppPauseControlIcon(); + } + } + private void CanAudioPauseContinueExec(object control, CanExecuteRoutedEventArgs e) + { + if ((AudioDevice != null) && (AudioDevice.PlaybackState != PlaybackState.Stopped)) + { + e.CanExecute = true; + } + else e.CanExecute = false; + } + + +#endregion + private void PlayFile (Entry entry) { IBinaryStream input = null; @@ -1008,7 +1259,29 @@ namespace GARbro.GUI else AudioDevice.Init (CurrentAudio); AudioDevice.PlaybackStopped += OnPlaybackStopped; + AudioDevice.Play(); + +#region ADL + if (AudioFileList.Count == 0) + AudioFileList.Add(entry); + appPauseAudioControl.Visibility = Visibility.Visible; + SetAppPauseControlIcon(); + + //this.app_notify_icon.ShowBalloonTip(2000, "Now playing:", entry.Name, Form.ToolTipIcon.Info); + trayShowBalloonTip( + 4, + guiStrings.MsgNowPlaying.Replace("{0}", ""), + String.Format(guiStrings.MsgNowPlaying, entry.Name) + ); + trayUpdate(String.Format(guiStrings.MsgNowPlaying, entry.Name)); + if (AudioFileList.Count > 1) + { + appNextAudioControl.Visibility = Visibility.Visible; + appPreviousAudioControl.Visibility = Visibility.Visible; + } +#endregion + appPlaybackControl.Visibility = Visibility.Visible; var fmt = CurrentAudio.WaveFormat; SetResourceText (string.Format (guiStrings.MsgPlaying, entry.Name, @@ -1042,6 +1315,31 @@ namespace GARbro.GUI SetResourceText (""); CurrentAudio = null; appPlaybackControl.Visibility = Visibility.Collapsed; + +#region ADL + trayUpdate(""); + if (AudioFileList.Count > 0 && AudioFileList.Count > ++CurrentAudioFileListIdx) + { + PlayFile(AudioFileList[CurrentAudioFileListIdx]); + } + else + { + CurrentAudioFileListIdx = 0; + if (isAudioLoop && AudioFileList.Count > 0) + { + PlayFile(AudioFileList[CurrentAudioFileListIdx]); + } + else + { + appPauseAudioControl.Visibility = Visibility.Collapsed; + appNextAudioControl.Visibility = Visibility.Collapsed; + appPreviousAudioControl.Visibility = Visibility.Collapsed; + AudioFileList.Clear(); + trayUpdate(guiStrings.MsgRunning); + } + } +#endregion + } catch (Exception X) { @@ -1479,6 +1777,11 @@ namespace GARbro.GUI Trace.WriteLine (X.Message, "Drop event failed"); } } + + private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) + { + + } } public class SortModeToBooleanConverter : IValueConverter @@ -1500,7 +1803,7 @@ namespace GARbro.GUI public class BooleanToCollapsedVisibilityConverter : IValueConverter { - #region IValueConverter Members +#region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { @@ -1514,7 +1817,7 @@ namespace GARbro.GUI throw new NotImplementedException(); } - #endregion +#endregion } public static class Commands @@ -1550,5 +1853,13 @@ namespace GARbro.GUI public static readonly RoutedCommand TroubleShooting = new RoutedCommand(); public static readonly RoutedCommand Descend = new RoutedCommand(); public static readonly RoutedCommand Ascend = new RoutedCommand(); +#region ADL + public static readonly RoutedCommand AudioPlayAll = new RoutedCommand(); + public static readonly RoutedCommand AudioLoopAll = new RoutedCommand(); + public static readonly RoutedCommand AudioStopAll = new RoutedCommand(); + public static readonly RoutedCommand AudioPauseContinue = new RoutedCommand(); + public static readonly RoutedCommand AudioNext = new RoutedCommand(); + public static readonly RoutedCommand AudioPrevious = new RoutedCommand(); +#endregion } } diff --git a/GUI/Strings/guiStrings.Designer.cs b/GUI/Strings/guiStrings.Designer.cs index 4e6eec1a..87472f1b 100644 --- a/GUI/Strings/guiStrings.Designer.cs +++ b/GUI/Strings/guiStrings.Designer.cs @@ -19,7 +19,7 @@ namespace GARbro.GUI.Strings { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class guiStrings { @@ -159,6 +159,42 @@ namespace GARbro.GUI.Strings { } } + /// + /// Looks up a localized string similar to Looping.... + /// + public static string CtxMenuAudioLoopAll { + get { + return ResourceManager.GetString("CtxMenuAudioLoopAll", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Continue / Pause. + /// + public static string CtxMenuAudioPauseContinue { + get { + return ResourceManager.GetString("CtxMenuAudioPauseContinue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playing.... + /// + public static string CtxMenuAudioPlayAll { + get { + return ResourceManager.GetString("CtxMenuAudioPlayAll", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stop playing.... + /// + public static string CtxMenuAudioStopAll { + get { + return ResourceManager.GetString("CtxMenuAudioStopAll", resourceCulture); + } + } + /// /// Looks up a localized string similar to _Close. /// @@ -834,6 +870,15 @@ namespace GARbro.GUI.Strings { } } + /// + /// Looks up a localized string similar to Now Playing: {0}. + /// + public static string MsgNowPlaying { + get { + return ResourceManager.GetString("MsgNowPlaying", resourceCulture); + } + } + /// /// Looks up a localized string similar to File {0} ///already exists. @@ -846,6 +891,15 @@ namespace GARbro.GUI.Strings { } } + /// + /// Looks up a localized string similar to Paused: {0}. + /// + public static string MsgPaused { + get { + return ResourceManager.GetString("MsgPaused", resourceCulture); + } + } + /// /// Looks up a localized string similar to Playing {0} / {3} / {2}bps / {1}Hz. /// @@ -864,6 +918,15 @@ namespace GARbro.GUI.Strings { } } + /// + /// Looks up a localized string similar to GARBro is running.... + /// + public static string MsgRunning { + get { + return ResourceManager.GetString("MsgRunning", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} file added to selection. /// diff --git a/GUI/Strings/guiStrings.resx b/GUI/Strings/guiStrings.resx index 8ac0b4ad..1e407a21 100644 --- a/GUI/Strings/guiStrings.resx +++ b/GUI/Strings/guiStrings.resx @@ -545,4 +545,25 @@ Overwrite? Preferences + + Looping... + + + Continue / Pause + + + Playing... + + + Stop playing... + + + Now Playing: {0} + + + Paused: {0} + + + GARBro is running... + \ No newline at end of file