/Application/GUI/Controls/Playback.xaml.cs

http://yet-another-music-application.googlecode.com/ · C# · 953 lines · 623 code · 138 blank · 192 comment · 119 complexity · c94bcab539fe64c044bc14d377f4041f MD5 · raw file

  1. /**
  2. * Playback.xaml.cs
  3. *
  4. * All buttons and controls used to manage playback such as
  5. * play, pause, next and previous along with seek, volume and
  6. * search.
  7. *
  8. * * * * * * * * *
  9. *
  10. * This code is part of the Stoffi Music Player Project.
  11. * Visit our website at: stoffiplayer.com
  12. *
  13. * This program is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU General Public License
  15. * as published by the Free Software Foundation; either version
  16. * 3 of the License, or (at your option) any later version.
  17. *
  18. * See stoffiplayer.com/license for more information.
  19. **/
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Linq;
  23. using System.Text;
  24. using System.Windows;
  25. using System.Windows.Controls;
  26. using System.Windows.Data;
  27. using System.Windows.Documents;
  28. using System.Windows.Input;
  29. using System.Windows.Media;
  30. using System.Windows.Media.Imaging;
  31. using System.Windows.Navigation;
  32. using System.Windows.Threading;
  33. using System.Windows.Shapes;
  34. namespace Stoffi
  35. {
  36. /// <summary>
  37. /// A playback control that contains all playback buttons, track information, volume and seek slides as well as a search box
  38. /// </summary>
  39. public partial class Playback : UserControl
  40. {
  41. #region Members
  42. public StoffiWindow ParentWindow;
  43. private BookmarkLayer bookmarkLayer;
  44. // compression constants
  45. private double startCompression = 800;
  46. private double volumeMaxWidth = 70;
  47. private double volumeMinWidth = 35;
  48. private double repshuMaxMargin = 10;
  49. private double repshuMinMargin = 0;
  50. private double searchMaxWidth = 200;
  51. private double searchMinWidth = 90;
  52. private double volumeMaxMargin = 10;
  53. private double volumeMinMargin = 0;
  54. #endregion
  55. #region Constructor
  56. /// <summary>
  57. /// Creates the playback control
  58. /// </summary>
  59. public Playback()
  60. {
  61. U.L(LogLevel.Debug, "PLAYBACK", "Initialize");
  62. InitializeComponent();
  63. U.L(LogLevel.Debug, "PLAYBACK", "Initialized");
  64. SettingsManager.PropertyChanged += new PropertyChangedWithValuesEventHandler(SettingsManager_PropertyChanged);
  65. SongProgress.ValueChanged -= new RoutedPropertyChangedEventHandler<double>(SongProgress_ValueChanged);
  66. SongProgress.Value = SettingsManager.Seek;
  67. SongProgress.ValueChanged += new RoutedPropertyChangedEventHandler<double>(SongProgress_ValueChanged);
  68. VolumeSlide.AutoToolTipPlacement = System.Windows.Controls.Primitives.AutoToolTipPlacement.TopLeft;
  69. U.L(LogLevel.Debug, "PLAYBACK", "Created");
  70. }
  71. #endregion
  72. #region Methods
  73. #region Public
  74. /// <summary>
  75. ///
  76. /// </summary>
  77. /// <param name="width"></param>
  78. public void Compress(double width)
  79. {
  80. if (width < startCompression)
  81. {
  82. double stretchFactor = (width - ParentWindow.MinWidth) / (startCompression - ParentWindow.MinWidth);
  83. double volumeWidth = volumeMinWidth + ((volumeMaxWidth - volumeMinWidth) * stretchFactor);
  84. double volumeMargin = volumeMinMargin + ((volumeMaxMargin - volumeMinMargin) * stretchFactor);
  85. double searchWidth = searchMinWidth + ((searchMaxWidth - searchMinWidth) * stretchFactor);
  86. double repshuMargin = repshuMinMargin + ((repshuMaxMargin - repshuMinMargin) * stretchFactor);
  87. VolumeSlide.Width = volumeWidth;
  88. VolumeSlide.Margin = new Thickness(volumeMargin, 0, volumeMargin, 0);
  89. Search.SearchContainer.Width = searchWidth;
  90. RepeatShuffleContainer.Margin = new Thickness(repshuMargin, 0, repshuMargin, 0);
  91. }
  92. else
  93. {
  94. VolumeSlide.Width = volumeMaxWidth;
  95. VolumeSlide.Margin = new Thickness(volumeMaxMargin, 0, volumeMaxMargin, 0);
  96. Search.SearchContainer.Width = searchMaxWidth;
  97. RepeatShuffleContainer.Margin = new Thickness(repshuMaxMargin, 0, repshuMaxMargin, 0);
  98. }
  99. }
  100. /// <summary>
  101. ///
  102. /// </summary>
  103. /// <param name="pos"></param>
  104. public void AddBookmark(double pos)
  105. {
  106. while (bookmarkLayer == null) ;
  107. bookmarkLayer.AddBookmark(pos);
  108. }
  109. /// <summary>
  110. ///
  111. /// </summary>
  112. /// <param name="pos"></param>
  113. public void RemoveBookmark(double pos)
  114. {
  115. while (bookmarkLayer == null) ;
  116. bookmarkLayer.RemoveBookmark(pos);
  117. }
  118. /// <summary>
  119. ///
  120. /// </summary>
  121. public void ClearBookmarks()
  122. {
  123. while (bookmarkLayer == null) ;
  124. bookmarkLayer.ClearBookmarks();
  125. }
  126. #endregion
  127. #region Private
  128. /// <summary>
  129. /// Updates the shuffle button to reflect the current Shuffle state
  130. /// </summary>
  131. private void UpdateShuffle()
  132. {
  133. switch (SettingsManager.Shuffle)
  134. {
  135. case true:
  136. ShuffleButton.Style = (Style)FindResource("ShuffleButtonStyle");
  137. break;
  138. case false:
  139. default:
  140. ShuffleButton.Style = (Style)FindResource("ShuffleGrayButtonStyle");
  141. break;
  142. }
  143. }
  144. /// <summary>
  145. /// Updates the repeat button to reflect the current Repeat state
  146. /// </summary>
  147. private void UpdateRepeat()
  148. {
  149. switch (SettingsManager.Repeat)
  150. {
  151. case RepeatState.RepeatAll:
  152. RepeatButton.Style = (Style)FindResource("RepeatAllButtonStyle");
  153. break;
  154. case RepeatState.RepeatOne:
  155. RepeatButton.Style = (Style)FindResource("RepeatOneButtonStyle");
  156. break;
  157. case RepeatState.NoRepeat:
  158. default:
  159. RepeatButton.Style = (Style)FindResource("RepeatGrayButtonStyle");
  160. break;
  161. }
  162. }
  163. /// <summary>
  164. /// Updates the information about the currently loaded track
  165. /// </summary>
  166. private void UpdateInfo()
  167. {
  168. if (SettingsManager.CurrentTrack == null)
  169. {
  170. InfoName.Text = U.T("PlaybackEmpty");
  171. InfoTimeMinus.Content = "N/A";
  172. InfoTimePlus.Content = "N/A";
  173. SongProgress.ValueChanged -= new RoutedPropertyChangedEventHandler<double>(SongProgress_ValueChanged);
  174. SongProgress.Value = SettingsManager.Seek;
  175. SongProgress.SecondValueWidth = 0;
  176. SongProgress.ValueChanged += new RoutedPropertyChangedEventHandler<double>(SongProgress_ValueChanged);
  177. }
  178. else
  179. {
  180. TrackData t = SettingsManager.CurrentTrack;
  181. InfoName.Text = t.Artist + " - " + t.Title;
  182. double pos = MediaManager.GetPosition();
  183. double len = MediaManager.GetLength();
  184. if (pos < 0) pos = 0;
  185. if (len < 0) len = 0;
  186. TimeSpan timePlus = new TimeSpan(0, 0, (int)pos);
  187. TimeSpan timeMinus = new TimeSpan(0, 0, (int)(len - pos));
  188. if (timePlus.TotalSeconds < 0)
  189. InfoTimePlus.Content = "N/A";
  190. else if (timePlus.TotalSeconds > 0)
  191. InfoTimePlus.Content = U.TimeSpanToString(timePlus);
  192. if (timeMinus.TotalSeconds < 0)
  193. InfoTimeMinus.Content = "N/A";
  194. else if (timeMinus.TotalSeconds > 0)
  195. InfoTimeMinus.Content = "-" + U.TimeSpanToString(timeMinus);
  196. double seek = (pos / len) * 10;
  197. if (timePlus.Seconds < 0 || Double.IsNaN(seek) || Double.IsInfinity(seek)) seek = 0;
  198. if (seek > 0 || SettingsManager.MediaState != MediaState.Playing)
  199. {
  200. SongProgress.ValueChanged -= new RoutedPropertyChangedEventHandler<double>(SongProgress_ValueChanged);
  201. SongProgress.Value = seek;
  202. SongProgress.ValueChanged += new RoutedPropertyChangedEventHandler<double>(SongProgress_ValueChanged);
  203. }
  204. }
  205. }
  206. #endregion
  207. #region Event handlers
  208. /// <summary>
  209. /// Invoked when the user clicks on pause/play
  210. /// </summary>
  211. /// <param name="sender">The sender of the event</param>
  212. /// <param name="e">The event data</param>
  213. private void PausePlay_Click(object sender, RoutedEventArgs e)
  214. {
  215. if (SettingsManager.MediaState == MediaState.Playing)
  216. MediaManager.Pause();
  217. else if (SettingsManager.CurrentTrack != null)
  218. MediaManager.Play();
  219. else if (ParentWindow.GetCurrentTrackList() != null)
  220. {
  221. if (ParentWindow.GetCurrentTrackList().SelectedItems.Count > 0)
  222. {
  223. TrackData track = (TrackData)ParentWindow.GetCurrentTrackList().SelectedItem;
  224. MediaManager.Load(track);
  225. MediaManager.Play();
  226. }
  227. else if (ParentWindow.GetCurrentTrackList().Items.Count > 0)
  228. {
  229. TrackData track = (TrackData)ParentWindow.GetCurrentTrackList().Items[0];
  230. MediaManager.Load(track);
  231. MediaManager.Play();
  232. }
  233. }
  234. }
  235. /// <summary>
  236. /// Invoked when the user clicks on next
  237. /// </summary>
  238. /// <param name="sender">The sender of the event</param>
  239. /// <param name="e">The event data</param>
  240. private void Next_Click(object sender, RoutedEventArgs e)
  241. {
  242. MediaManager.Next(true);
  243. }
  244. /// <summary>
  245. /// Invoked when the user clicks on previous
  246. /// </summary>
  247. /// <param name="sender">The sender of the event</param>
  248. /// <param name="e">The event data</param>
  249. private void Previous_Click(object sender, RoutedEventArgs e)
  250. {
  251. MediaManager.Previous();
  252. }
  253. /// <summary>
  254. /// Invoked when the user clicks on repeat
  255. /// </summary>
  256. /// <param name="sender">The sender of the event</param>
  257. /// <param name="e">The event data</param>
  258. public void Repeat_Click(object sender, RoutedEventArgs e)
  259. {
  260. switch (SettingsManager.Repeat)
  261. {
  262. case RepeatState.RepeatAll:
  263. SettingsManager.Repeat = RepeatState.RepeatOne;
  264. break;
  265. case RepeatState.RepeatOne:
  266. SettingsManager.Repeat = RepeatState.NoRepeat;
  267. break;
  268. case RepeatState.NoRepeat:
  269. default:
  270. SettingsManager.Repeat = RepeatState.RepeatAll;
  271. break;
  272. }
  273. UpdateRepeat();
  274. }
  275. /// <summary>
  276. /// Invoked when the user clicks on shuffle
  277. /// </summary>
  278. /// <param name="sender">The sender of the event</param>
  279. /// <param name="e">The event data</param>
  280. public void Shuffle_Click(object sender, RoutedEventArgs e)
  281. {
  282. SettingsManager.Shuffle = !SettingsManager.Shuffle;
  283. UpdateShuffle();
  284. }
  285. /// <summary>
  286. /// Invoked when the user changes the volume slider
  287. /// </summary>
  288. /// <param name="sender">The sender of the event</param>
  289. /// <param name="e">The event data</param>
  290. private void VolumeSlide_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
  291. {
  292. if (MediaManager.IsInitialized)
  293. SettingsManager.Volume = VolumeSlide.Value;
  294. }
  295. /// <summary>
  296. /// Invoked when the user scrolls over the volume slider
  297. /// </summary>
  298. /// <param name="sender">The sender of the event</param>
  299. /// <param name="e">The event data</param>
  300. private void VolumeSlide_MouseWheel(object sender, MouseWheelEventArgs e)
  301. {
  302. if (e.Delta > 0)
  303. VolumeSlide.Value+=5;
  304. else
  305. VolumeSlide.Value-=5;
  306. }
  307. /// <summary>
  308. /// Invoked when the user changes the seek slider
  309. /// </summary>
  310. /// <param name="sender">The sender of the event</param>
  311. /// <param name="e">The event data</param>
  312. public void SongProgress_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
  313. {
  314. if (MediaManager.IsInitialized)
  315. {
  316. SettingsManager.Seek = SongProgress.Value;
  317. double pos = (ParentWindow.PlaybackControls.SongProgress.Value / 10) * MediaManager.GetLength();
  318. double rem = MediaManager.GetLength() - pos;
  319. TimeSpan timePlus = new TimeSpan(0, 0, (int)pos);
  320. TimeSpan timeMinus = new TimeSpan(0, 0, (int)rem);
  321. if (rem < 0)
  322. ParentWindow.PlaybackControls.InfoTimePlus.Content = "N/A";
  323. else
  324. ParentWindow.PlaybackControls.InfoTimePlus.Content = U.TimeSpanToString(timePlus);
  325. if (rem < 0)
  326. ParentWindow.PlaybackControls.InfoTimeMinus.Content = "N/A";
  327. else
  328. ParentWindow.PlaybackControls.InfoTimeMinus.Content = "-" + U.TimeSpanToString(timeMinus);
  329. }
  330. }
  331. /// <summary>
  332. /// Invoked when the user modifies the text in the search box
  333. /// </summary>
  334. /// <param name="e">The event data</param>
  335. private void Search_TextChanged(SearchBoxEventArgs e)
  336. {
  337. String csn = SettingsManager.CurrentSelectedNavigation;
  338. if (csn == null) return;
  339. // switch to currently active navigation
  340. if (csn == "NowPlaying")
  341. {
  342. ParentWindow.NavigationPane.SwitchNavigation(SettingsManager.CurrentActiveNavigation);
  343. Search.IsActive = true;
  344. Search.Text = e.Text;
  345. Search.Position = e.Text.Count();
  346. return;
  347. }
  348. if (ParentWindow == null) return;
  349. ParentWindow.GetCurrentTrackList().Filter = e.Text;
  350. if (csn == "YouTube")
  351. {
  352. ParentWindow.YouTubeContainer.Search(e.Text);
  353. return;
  354. }
  355. if (csn == "History" || SettingsManager.SearchPolicy == SearchPolicy.Global)
  356. SettingsManager.HistoryListConfig.Filter = e.Text;
  357. if (csn == "Queue" || SettingsManager.SearchPolicy == SearchPolicy.Global)
  358. SettingsManager.QueueListConfig.Filter = e.Text;
  359. if (csn == "Library" || SettingsManager.SearchPolicy == SearchPolicy.Global)
  360. SettingsManager.FileListConfig.Filter = e.Text;
  361. if (SettingsManager.SearchPolicy == SearchPolicy.Global)
  362. {
  363. foreach (PlaylistData pl in SettingsManager.Playlists)
  364. pl.ListConfig.Filter = e.Text;
  365. }
  366. else
  367. {
  368. if (csn.StartsWith("Playlist:") && SettingsManager.SearchPolicy == SearchPolicy.Partial)
  369. foreach (PlaylistData pl in SettingsManager.Playlists)
  370. pl.ListConfig.Filter = e.Text;
  371. else if (csn.StartsWith("Playlist:"))
  372. {
  373. PlaylistData p = PlaylistManager.FindPlaylist(csn.Split(new[]{':'},2)[1]);
  374. if (p != null) p.ListConfig.Filter = e.Text;
  375. }
  376. }
  377. }
  378. /// <summary>
  379. /// Invoked when the user selects to add a search query to an existing playlist
  380. /// </summary>
  381. /// <param name="e">The event data</param>
  382. private void Search_AddClicked(SearchBoxAddEventArgs e)
  383. {
  384. List<object> tracks = new List<object>();
  385. foreach (TrackData track in ParentWindow.GetCurrentTrackList().Items)
  386. tracks.Add(track);
  387. PlaylistManager.AddToPlaylist(tracks, e.PlaylistName);
  388. }
  389. /// <summary>
  390. /// Invoked when the user selects to add a search query to a new playlist
  391. /// </summary>
  392. /// <param name="e">The event data</param>
  393. private void Search_AddToNewClicked(SearchBoxAddToNewEventArgs e)
  394. {
  395. ParentWindow.NavigationPane.AddToPlaylistQueue.Clear();
  396. foreach (TrackData track in ParentWindow.GetCurrentTrackList().Items)
  397. ParentWindow.NavigationPane.AddToPlaylistQueue.Add(track);
  398. ParentWindow.NavigationPane.CreateNewPlaylistETB.IsInEditMode = true;
  399. }
  400. /// <summary>
  401. /// Invoked when the user selects to remove a search query from a playlist
  402. /// </summary>
  403. /// <param name="e">The event data</param>
  404. private void Search_RemoveClicked(SearchBoxRemoveEventArgs e)
  405. {
  406. List<TrackData> tracks = new List<TrackData>();
  407. foreach (TrackData track in ParentWindow.GetCurrentTrackList().Items)
  408. tracks.Add(track);
  409. PlaylistManager.RemoveFromPlaylist(tracks, e.PlaylistName);
  410. }
  411. /// <summary>
  412. /// Invoked when the user clears the search box
  413. /// </summary>
  414. private void Search_Cleared()
  415. {
  416. //ParentWindow.GetCurrentTrackList().Items.Filter = null;
  417. // TODO: move code below into a function
  418. String csn = SettingsManager.CurrentSelectedNavigation;
  419. if (csn == "History" || SettingsManager.SearchPolicy == SearchPolicy.Global)
  420. SettingsManager.HistoryListConfig.Filter = "";
  421. if (csn == "Queue" || SettingsManager.SearchPolicy == SearchPolicy.Global)
  422. SettingsManager.QueueListConfig.Filter = "";
  423. if (csn == "Library" || SettingsManager.SearchPolicy == SearchPolicy.Global)
  424. SettingsManager.FileListConfig.Filter = "";
  425. if (SettingsManager.SearchPolicy == SearchPolicy.Global)
  426. {
  427. foreach (PlaylistData pl in SettingsManager.Playlists)
  428. pl.ListConfig.Filter = "";
  429. }
  430. else
  431. {
  432. if (csn.StartsWith("Playlist:") && SettingsManager.SearchPolicy == SearchPolicy.Partial)
  433. foreach (PlaylistData pl in SettingsManager.Playlists)
  434. pl.ListConfig.Filter = "";
  435. else if (csn.StartsWith("Playlist:"))
  436. PlaylistManager.FindPlaylist(csn.Split(new[] { ':' }, 2)[1]).ListConfig.Filter = "";
  437. }
  438. }
  439. /// <summary>
  440. /// Invoked when the control is loded
  441. /// </summary>
  442. /// <param name="sender">The sender of the event</param>
  443. /// <param name="e">The event data</param>
  444. private void Control_Loaded(object sender, RoutedEventArgs e)
  445. {
  446. bookmarkLayer = new BookmarkLayer(SongProgress);
  447. bookmarkLayer.RemoveClicked += new EventHandler(RemoveBookmark_Click);
  448. bookmarkLayer.Clicked += new BookmarkEventHandler(Bookmark_Clicked);
  449. AdornerLayer al = AdornerLayer.GetAdornerLayer(SongProgress);
  450. al.Add(bookmarkLayer);
  451. if (SettingsManager.CurrentTrack != null)
  452. {
  453. foreach (double b in MediaManager.GetLibrarySourceTrack(SettingsManager.CurrentTrack).Bookmarks)
  454. {
  455. bookmarkLayer.AddBookmark(b);
  456. }
  457. }
  458. if (System.Windows.Forms.VisualStyles.VisualStyleInformation.DisplayName == "")
  459. {
  460. InfoWindow.BorderThickness = new Thickness(1, 1, 0, 0);
  461. InfoWindow.BorderBrush = SystemColors.ControlDarkBrush;
  462. InfoWindow.CornerRadius = new CornerRadius(0);
  463. InfoWindowBorder1.BorderThickness = new Thickness(0, 0, 1, 1);
  464. InfoWindowBorder1.BorderBrush = SystemColors.ControlLightLightBrush;
  465. InfoWindowBorder1.CornerRadius = new CornerRadius(0);
  466. InfoWindowBorder2.BorderThickness = new Thickness(1, 1, 0, 0);
  467. InfoWindowBorder2.BorderBrush = null;
  468. InfoWindowBorder2.CornerRadius = new CornerRadius(0);
  469. InfoWindowBorder3.BorderThickness = new Thickness(0, 0, 1, 1);
  470. InfoWindowBorder3.BorderBrush = null;
  471. InfoWindowBorder3.CornerRadius = new CornerRadius(0);
  472. InfoWindowInner.Background = SystemColors.ControlBrush;
  473. InfoTimeMinus.Foreground = SystemColors.ControlTextBrush;
  474. InfoTimePlus.Foreground = SystemColors.ControlTextBrush;
  475. InfoName.Foreground = SystemColors.ControlTextBrush;
  476. }
  477. UpdateInfo();
  478. UpdateShuffle();
  479. UpdateRepeat();
  480. }
  481. /// <summary>
  482. /// Invoked when the user removes a bookmark
  483. /// </summary>
  484. /// <param name="sender">The sender of the event</param>
  485. /// <param name="e">The event data</param>
  486. private void RemoveBookmark_Click(object sender, EventArgs e)
  487. {
  488. DispatchRemoveBookmarkClicked(sender, e);
  489. }
  490. /// <summary>
  491. /// Invoked when the user clicks on a bookmark
  492. /// </summary>
  493. /// <param name="sender">The sender of the event</param>
  494. /// <param name="e">The event data</param>
  495. private void Bookmark_Clicked(object sender, BookmarkEventArgs e)
  496. {
  497. this.SongProgress.Value = e.Position / 10;
  498. }
  499. /// <summary>
  500. /// Invoked when a property of the settings manager changes
  501. /// </summary>
  502. /// <param name="sender">The sender of the event</param>
  503. /// <param name="e">The event data</param>
  504. private void SettingsManager_PropertyChanged(object sender, PropertyChangedWithValuesEventArgs e)
  505. {
  506. Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
  507. {
  508. switch (e.PropertyName)
  509. {
  510. case "Seek":
  511. UpdateInfo();
  512. break;
  513. case "BufferSize":
  514. SongProgress.SecondValue = SettingsManager.BufferSize;
  515. break;
  516. case "Volume":
  517. VolumeSlide.Value = SettingsManager.Volume;
  518. Console.WriteLine("setting volume to: " + VolumeSlide.Value);
  519. break;
  520. case "Shuffle":
  521. UpdateShuffle();
  522. break;
  523. case "Repeat":
  524. UpdateRepeat();
  525. break;
  526. case "CurrentTrack":
  527. UpdateInfo();
  528. ClearBookmarks();
  529. if (SettingsManager.CurrentTrack != null)
  530. {
  531. TrackData libraryTrack = MediaManager.GetLibrarySourceTrack(SettingsManager.CurrentTrack);
  532. if (libraryTrack.Bookmarks != null)
  533. foreach (double b in libraryTrack.Bookmarks)
  534. AddBookmark(b);
  535. }
  536. break;
  537. case "MediaState":
  538. switch (SettingsManager.MediaState)
  539. {
  540. case MediaState.Playing:
  541. PausePlayButton.Style = (Style)FindResource("PauseButtonStyle");
  542. break;
  543. case MediaState.Paused:
  544. case MediaState.Stopped:
  545. PausePlayButton.Style = (Style)FindResource("PlayButtonStyle");
  546. break;
  547. }
  548. break;
  549. }
  550. }));
  551. }
  552. #endregion
  553. #endregion
  554. #region Events
  555. /// <summary>
  556. ///
  557. /// </summary>
  558. public event EventHandler RemoveBookmarkClicked;
  559. /// <summary>
  560. ///
  561. /// </summary>
  562. /// <param name="sender"></param>
  563. /// <param name="e"></param>
  564. public void DispatchRemoveBookmarkClicked(object sender, EventArgs e)
  565. {
  566. if (RemoveBookmarkClicked != null)
  567. {
  568. RemoveBookmarkClicked(sender, e);
  569. }
  570. }
  571. #endregion
  572. }
  573. /// <summary>
  574. /// Describes the layer above the seek bar which holds the bookmarks
  575. /// </summary>
  576. public class BookmarkLayer : Adorner
  577. {
  578. #region Members
  579. private VisualCollection visualChildren;
  580. private Grid grid;
  581. private List<ColumnDefinition> spacers = new List<ColumnDefinition>();
  582. public List<Bookmark> bookmarks = new List<Bookmark>();
  583. public event EventHandler RemoveClicked;
  584. public event BookmarkEventHandler Clicked;
  585. #endregion
  586. #region Constructor
  587. /// <summary>
  588. /// Creates a Bookmarklayer
  589. /// </summary>
  590. /// <param name="adornedElement"></param>
  591. public BookmarkLayer(UIElement adornedElement)
  592. : base(adornedElement)
  593. {
  594. visualChildren = new VisualCollection(this);
  595. grid = new Grid();
  596. grid.Margin = new Thickness(0, 1, 0, 0);
  597. visualChildren.Add(grid);
  598. }
  599. #endregion
  600. #region Methods
  601. #region Public
  602. /// <summary>
  603. ///
  604. /// </summary>
  605. /// <param name="pos"></param>
  606. public void AddBookmark(double pos)
  607. {
  608. double bmWidth = 4.0;
  609. double MyWidth = this.ActualWidth;
  610. if (MyWidth < 147) MyWidth = 147;
  611. double posInPixels = MyWidth * (pos / 100);
  612. //if (posInPixels < (bmWidth / 2) || posInPixels > this.ActualWidth - (bmWidth / 2)) return;
  613. double width = posInPixels;
  614. double i = 0;
  615. ColumnDefinition newCd;
  616. ColumnDefinition bmCd;
  617. Bookmark bm;
  618. foreach (ColumnDefinition cd in spacers)
  619. {
  620. width = posInPixels - i;
  621. i += cd.Width.Value;
  622. if (i - (bmWidth / 2) < posInPixels && posInPixels <= i + (bmWidth * 1.5)) return;
  623. if (posInPixels < i)
  624. {
  625. newCd = new ColumnDefinition();
  626. newCd.Width = new GridLength(width - (bmWidth/2));
  627. bmCd = new ColumnDefinition();
  628. bmCd.Width = new GridLength(bmWidth);
  629. int c = grid.ColumnDefinitions.IndexOf(cd);
  630. grid.ColumnDefinitions.Insert(c, bmCd);
  631. grid.ColumnDefinitions.Insert(c, newCd);
  632. cd.Width = new GridLength(cd.Width.Value - (width + (bmWidth * 1.5)));
  633. bm = new Bookmark();
  634. bm.Position = pos;
  635. bm.RemoveClicked += new EventHandler(Bookmark_RemoveClicked);
  636. bm.Clicked += new BookmarkEventHandler(Bookmark_Clicked);
  637. foreach (Bookmark b in bookmarks)
  638. {
  639. if (b.Position > bm.Position)
  640. {
  641. spacers.Insert(bookmarks.IndexOf(b), newCd);
  642. bookmarks.Insert(bookmarks.IndexOf(b), bm);
  643. break;
  644. }
  645. }
  646. int j = 1;
  647. foreach (Bookmark b in bookmarks)
  648. {
  649. j += 2;
  650. if (b.Position > bm.Position)
  651. Grid.SetColumn(b, j);
  652. }
  653. Grid.SetColumn(bm, c + 1);
  654. grid.Children.Add(bm);
  655. return;
  656. }
  657. i += 2.0;
  658. }
  659. width = posInPixels - i;
  660. newCd = new ColumnDefinition();
  661. newCd.Width = new GridLength(width - (bmWidth / 2));
  662. spacers.Add(newCd);
  663. bmCd = new ColumnDefinition();
  664. bmCd.Width = new GridLength(bmWidth);
  665. grid.ColumnDefinitions.Add(newCd);
  666. grid.ColumnDefinitions.Add(bmCd);
  667. bm = new Bookmark();
  668. bm.Position = pos;
  669. bm.RemoveClicked += new EventHandler(Bookmark_RemoveClicked);
  670. bm.Clicked += new BookmarkEventHandler(Bookmark_Clicked);
  671. bookmarks.Add(bm);
  672. Grid.SetColumn(bm, grid.ColumnDefinitions.Count - 1);
  673. grid.Children.Add(bm);
  674. }
  675. /// <summary>
  676. ///
  677. /// </summary>
  678. /// <param name="pos"></param>
  679. public void RemoveBookmark(double pos)
  680. {
  681. Bookmark bookmarkToRemove = null;
  682. int i = 0;
  683. foreach (Bookmark m in bookmarks)
  684. {
  685. if (m.Position == pos)
  686. {
  687. i = bookmarks.IndexOf(m);
  688. bookmarkToRemove = m;
  689. break;
  690. }
  691. }
  692. if (bookmarkToRemove != null)
  693. {
  694. if (i == bookmarks.Count - 1)
  695. {
  696. grid.ColumnDefinitions.Remove(grid.ColumnDefinitions.Last());
  697. grid.ColumnDefinitions.Remove(grid.ColumnDefinitions.Last());
  698. grid.Children.Remove(bookmarks.Last());
  699. spacers.Remove(spacers.Last());
  700. bookmarks.Remove(bookmarks.Last());
  701. }
  702. else
  703. {
  704. ColumnDefinition cd1 = grid.ColumnDefinitions[(2 * i)];
  705. ColumnDefinition cd2 = grid.ColumnDefinitions[(2 * i) + 1];
  706. ColumnDefinition cd3 = grid.ColumnDefinitions[(2 * i) + 2];
  707. cd3.Width = new GridLength(cd3.Width.Value + cd2.Width.Value + cd1.Width.Value);
  708. grid.ColumnDefinitions.Remove(cd1);
  709. grid.ColumnDefinitions.Remove(cd2);
  710. grid.Children.Remove(bookmarkToRemove);
  711. spacers.Remove(cd1);
  712. bookmarks.Remove(bookmarkToRemove);
  713. foreach (Bookmark b in bookmarks)
  714. Grid.SetColumn(b, bookmarks.IndexOf(b) * 2 + 1);
  715. }
  716. }
  717. }
  718. /// <summary>
  719. ///
  720. /// </summary>
  721. public void ClearBookmarks()
  722. {
  723. bookmarks.Clear();
  724. spacers.Clear();
  725. grid.ColumnDefinitions.Clear();
  726. grid.Children.Clear();
  727. }
  728. #endregion
  729. #region Event handlers
  730. /// <summary>
  731. ///
  732. /// </summary>
  733. /// <param name="sender"></param>
  734. /// <param name="e"></param>
  735. private void Bookmark_RemoveClicked(object sender, EventArgs e)
  736. {
  737. DispatchRemoveClicked(sender, e);
  738. }
  739. /// <summary>
  740. ///
  741. /// </summary>
  742. /// <param name="sender"></param>
  743. /// <param name="e"></param>
  744. private void Bookmark_Clicked(object sender, BookmarkEventArgs e)
  745. {
  746. DispatchClicked(sender, e);
  747. }
  748. #endregion
  749. #endregion
  750. #region Overrides
  751. /// <summary>
  752. ///
  753. /// </summary>
  754. /// <param name="finalSize"></param>
  755. /// <returns></returns>
  756. protected override Size ArrangeOverride(Size finalSize)
  757. {
  758. double bmWidth = 4.0;
  759. double x = 0;
  760. double y = 0;
  761. grid.Arrange(new Rect(x, y, finalSize.Width, finalSize.Height));
  762. double i = 0.0;
  763. foreach (Bookmark bm in bookmarks)
  764. {
  765. double posInPixels = finalSize.Width * (bm.Position / 100);
  766. ColumnDefinition cd = grid.ColumnDefinitions[(2 * bookmarks.IndexOf(bm))];
  767. grid.ColumnDefinitions[(2 * bookmarks.IndexOf(bm)) + 1].Width = new GridLength(bmWidth);
  768. Grid.SetColumn(bm, 1+ (bookmarks.IndexOf(bm) * 2));
  769. if (posInPixels - i - (bmWidth / 2) > 0)
  770. cd.Width = new GridLength(posInPixels - i - (bmWidth / 2));
  771. else
  772. cd.Width = new GridLength(0);
  773. i += cd.Width.Value + bmWidth;
  774. }
  775. return finalSize;
  776. }
  777. /// <summary>
  778. ///
  779. /// </summary>
  780. protected override int VisualChildrenCount { get { return visualChildren.Count; } }
  781. /// <summary>
  782. ///
  783. /// </summary>
  784. /// <param name="index"></param>
  785. /// <returns></returns>
  786. protected override Visual GetVisualChild(int index) { return visualChildren[index]; }
  787. #endregion
  788. #region Events
  789. /// <summary>
  790. ///
  791. /// </summary>
  792. /// <param name="sender"></param>
  793. /// <param name="e"></param>
  794. public void DispatchRemoveClicked(object sender, EventArgs e)
  795. {
  796. if (RemoveClicked != null)
  797. {
  798. RemoveClicked(sender, e);
  799. }
  800. }
  801. /// <summary>
  802. ///
  803. /// </summary>
  804. /// <param name="sender"></param>
  805. /// <param name="e"></param>
  806. public void DispatchClicked(object sender, BookmarkEventArgs e)
  807. {
  808. if (Clicked != null)
  809. {
  810. Clicked(sender, e);
  811. }
  812. }
  813. #endregion
  814. }
  815. }