Re: [Banshee-List] [PATCH] Fix repeat/shuffle buttons & logic



Attached updated patch against trunk and necessary resources (drop into
ThickClient's Resources directory).

On Sun, 24 Feb 2008 04:58:14 +0000, Alex Hixon
<hixon alexander mediati org> wrote:
> Hi all,
> 
> Posting this patch here for some review/discussion.
> 
> There are really two major changes that this patch makes, the first being
> changing the API of ICanonicalPlaybackController and
> IBasicPlaybackController. Basically, all I'm doing here is changing Next
> ()
> to Next (bool restartAtEnd). If restartAtEnd is true, the implementing
> class shouldn't stop playback merely because there are no more tracks to
> play linearly, it should queue up the first track if there are none left.
> Anyway, simple stuff.
> 
> The other issue that'll probably get a bit more discussion is the way we
> handle changing the Sensitive state on the shuffle/repeat toggle button
> widgets. At the moment, it should be possible to do:
> (action_service.UIManager.GetWidget
("/FooterToolbar/ShuffleToggleButton")
> as Widget).Sensitive = false;, but this doesn't quite work for some
> reason.
> Instead, we end up getting a GtkMenuSeperator widget (at least, that's
> what
> I think it was called - this is off the top of my head). If we loop
> through
> the child elements of FooterToolbar, we end up with something like this:
> 
> ShuffleToggleButton | Separator | RepeatToggleButton | Separator |
> StatusBar | Separator | TrackMetadataAction
> 
> So, from the looks of things, it's getting the widget /adjacent/ to the
> widget we really want. So, at the moment, to work around this, we loop
> through the children of FooterToolbar and find items that are of type
> MultiStateToggleButton, and set their Sensitive value to false. Not sure
> if
> this is a problem with the way I'm approaching the issue, or a bug in
> Gtk#.
> 
> Anyway, the attached patch works as advertised - it adds support for the
> shuffle and repeat footer togglebuttons, and implements the necessary
> logic
> to drive them all. It also disables shuffle and repeat while we're
looking
> at the Last.fm radio source.
> 
> Comments, suggestions on the implementation?
> 
> Cheers,
> Alex Hixon
-- 
Cheers,
Alex Hixon
Index: Extensions/Banshee.NotificationArea/Banshee.NotificationArea/TrackInfoPopup.cs
===================================================================
--- Extensions/Banshee.NotificationArea/Banshee.NotificationArea/TrackInfoPopup.cs	(revision 3319)
+++ Extensions/Banshee.NotificationArea/Banshee.NotificationArea/TrackInfoPopup.cs	(working copy)
@@ -55,7 +55,7 @@
             
             // Position label and linear progress bar
             HBox position_box = new HBox ();
-            position_box.Spacing = 10;
+            //position_box.Spacing = 10;
             
             position_label = new Label ();
             position_label.Xalign = 0.0f;
Index: Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs
===================================================================
--- Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs	(revision 3319)
+++ Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs	(working copy)
@@ -47,6 +47,9 @@
 using Banshee.MediaEngine;
 using Banshee.Collection;
 using Banshee.ServiceStack;
+
+using Banshee.Gui;
+using Banshee.Gui.Widgets;
  
 namespace Banshee.Lastfm.Radio
 {
@@ -174,16 +177,50 @@
             OnUpdated ();
         }
         
+        private void SetStatusIconSensitive (bool val) {
+            Toolbar footer = (action_service.UIManager.GetWidget ("/FooterToolbar") as Toolbar);
+            
+            foreach (Widget child in footer.Children) {
+                try {
+                    GenericToolItem<Gtk.Widget> w = (GenericToolItem<Gtk.Widget>) child;
+                    
+                    if (w.Widget is MultiStateToggleButton) {
+                        w.Widget.Sensitive = val;
+                    }
+                } catch {
+                }
+            }
+        }
+        
         private bool shuffle;
+        private int repeat;
+        private InterfaceActionService action_service;
         public override void Activate ()
         {
+            if (action_service == null) {
+                action_service = ServiceManager.Get<InterfaceActionService> ("InterfaceActionService");
+            }
+            
             base.Activate ();
-            //shuffle = (action_service.GlobalActions ["ShuffleAction"] as ToggleAction).Active;
-            //(action_service.GlobalActions ["ShuffleAction"] as ToggleAction).Active = false;
-            //Globals.ActionManager["ShuffleAction"].Sensitive = false;
+            SetStatusIconSensitive (false);
+            shuffle = (action_service.PlaybackActions ["ShuffleAction"] as ToggleAction).Active;
+            (action_service.PlaybackActions ["ShuffleAction"] as ToggleAction).Active = false;
+            action_service.PlaybackActions ["ShuffleAction"].Sensitive = false;
+            
+            if ((action_service.PlaybackActions ["RepeatNoneAction"] as ToggleAction).Active) {
+                repeat = 0;
+            } else if ((action_service.PlaybackActions ["RepeatAllAction"] as ToggleAction).Active) {
+                repeat = 1;
+            } else {
+                repeat = 2;
+            }
+            
+            (action_service.PlaybackActions ["RepeatNoneAction"] as ToggleAction).Active = true;
+            
+            action_service.PlaybackActions ["RepeatNoneAction"].Sensitive = false;
+            action_service.PlaybackActions ["RepeatAllAction"].Sensitive = false;
+            action_service.PlaybackActions ["RepeatSingleAction"].Sensitive = false;
 
-            //action_service.GlobalActions ["PreviousAction"].Sensitive = false;
-
             // We lazy load the Last.fm connection, so if we're not already connected, do it
             if (lastfm.Connection.State == ConnectionState.Connected)
                 TuneAndLoad ();
@@ -206,10 +243,22 @@
 
         public override void Deactivate ()
         {
-            //(Globals.ActionManager["ShuffleAction"] as ToggleAction).Active = shuffle;
-            //Globals.ActionManager["ShuffleAction"].Sensitive = true;
+            (action_service.PlaybackActions ["ShuffleAction"] as ToggleAction).Active = shuffle;
+            action_service.PlaybackActions ["ShuffleAction"].Sensitive = true;
 
-            //Globals.ActionManager["PreviousAction"].Sensitive = true;
+            action_service.PlaybackActions ["PreviousAction"].Sensitive = true;
+            
+            SetStatusIconSensitive (true);
+            
+            action_service.PlaybackActions ["RepeatNoneAction"].Sensitive = true;
+            action_service.PlaybackActions ["RepeatAllAction"].Sensitive = true;
+            action_service.PlaybackActions ["RepeatSingleAction"].Sensitive = true;
+            
+            if (repeat == 1) {
+                (action_service.PlaybackActions ["RepeatAllAction"] as ToggleAction).Active = true;
+            } else if (repeat == 2) {
+                (action_service.PlaybackActions ["RepeatSingleAction"] as ToggleAction).Active = true;
+            }
         }
 
         // Last.fm requires you to 'tune' to a station before requesting a track list/playing it
Index: Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
===================================================================
--- Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	(revision 3319)
+++ Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	(working copy)
@@ -190,10 +190,10 @@
         
         void IBasicPlaybackController.First ()
         {
-            ((IBasicPlaybackController)this).Next ();
+            ((IBasicPlaybackController)this).Next (false);
         }
         
-        void IBasicPlaybackController.Next ()
+        void IBasicPlaybackController.Next (bool restartAtEnd)
         {
             RemoveFirstTrack ();
             
Index: Clients/Nereid/Nereid/PlayerInterface.cs
===================================================================
--- Clients/Nereid/Nereid/PlayerInterface.cs	(revision 3319)
+++ Clients/Nereid/Nereid/PlayerInterface.cs	(working copy)
@@ -57,8 +57,8 @@
         // Major Layout Components
         private VBox primary_vbox;
         private Toolbar header_toolbar;
+        private Toolbar footer_toolbar;
         private HPaned views_pane;
-        private HBox footer_box;
         private ViewContainer view_container;
         
         // Major Interaction Components
@@ -196,28 +196,33 @@
 
         private void BuildFooter ()
         {
-            footer_box = new HBox ();
-            footer_box.Spacing = 2;
+            footer_toolbar = (Toolbar)ActionService.UIManager.GetWidget ("/FooterToolbar");
+            footer_toolbar.ShowArrow = false;
+            footer_toolbar.ToolbarStyle = ToolbarStyle.BothHoriz;
+            footer_toolbar.IconSize = IconSize.Menu;
 
             status_label = new Label ();
             status_label.ModifyFg (StateType.Normal, Hyena.Gui.GtkUtilities.ColorBlend (
                 status_label.Style.Foreground (StateType.Normal), status_label.Style.Background (StateType.Normal)));
             
-            ActionButton song_properties_button = new ActionButton
+            /*ActionButton song_properties_button = new ActionButton
                 (ActionService.TrackActions["TrackPropertiesAction"]);
             song_properties_button.IconSize = IconSize.Menu;
             song_properties_button.Padding = 0;
-            song_properties_button.LabelVisible = false;
+            song_properties_button.LabelVisible = false;*/
             
-            //footer_box.PackStart (shuffle_toggle_button, false, false, 0);
-            //footer_box.PackStart (repeat_toggle_button, false, false, 0);
-            footer_box.PackStart (status_label, true, true, 0);
-            footer_box.PackStart (song_properties_button, false, false, 0);
+            ActionService.PopulateToolbarPlaceholder (footer_toolbar, "/FooterToolbar/Statusbar", status_label, true);
+            
+            MultiStateToggleButton shuffle_toggle_button = new ShuffleToggleButton (ActionService);
+            ActionService.PopulateToolbarPlaceholder (footer_toolbar, "/FooterToolbar/ShuffleToggleAction", shuffle_toggle_button);
+            
+            MultiStateToggleButton repeat_toggle_button = new RepeatToggleButton (ActionService);
+            ActionService.PopulateToolbarPlaceholder (footer_toolbar, "/FooterToolbar/RepeatToggleAction", repeat_toggle_button);
 
             Alignment align = new Alignment (0.5f, 0.5f, 1.0f, 1.0f);
-            align.TopPadding = 2;
+            align.TopPadding = 0;
             align.BottomPadding = 0;
-            align.Add (footer_box);
+            align.Add (footer_toolbar);
             align.ShowAll ();
 
             primary_vbox.PackStart (align, false, true, 0);
@@ -264,6 +269,7 @@
             };
             
             header_toolbar.ExposeEvent += OnHeaderToolbarExposeEvent;
+            footer_toolbar.ExposeEvent += OnFooterToolbarExposeEvent;
         }
         
 #endregion
@@ -364,6 +370,19 @@
             }
         }
         
+        private void OnFooterToolbarExposeEvent (object o, ExposeEventArgs args)
+        {
+            // This forces the toolbar to look like it's just a regular plain container
+            // since the stock toolbar look makes Banshee look ugly.
+            footer_toolbar.GdkWindow.DrawRectangle (Style.BackgroundGC (footer_toolbar.State), 
+                true, footer_toolbar.Allocation);
+            
+            // Manually expose all the toolbar's children
+            foreach (Widget child in footer_toolbar.Children) {
+                footer_toolbar.PropagateExpose (child, args.Event);
+            }
+        }
+        
 #endregion
 
 #region Implement Interfaces
Index: Core/Banshee.ThickClient/Banshee.Gui/ToggleStates.cs
===================================================================
--- Core/Banshee.ThickClient/Banshee.Gui/ToggleStates.cs	(revision 0)
+++ Core/Banshee.ThickClient/Banshee.Gui/ToggleStates.cs	(revision 0)
@@ -0,0 +1,83 @@
+// 
+// ToggleStates.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2005-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+ 
+using System;
+using Mono.Unix;
+using Banshee.Widgets;
+
+namespace Banshee.Gui
+{
+    public class RepeatNoneToggleState : ToggleState
+    {
+        public RepeatNoneToggleState()
+        {
+            Icon = IconThemeUtils.LoadIcon (16, "view-sort-descending");
+            Label = Catalog.GetString("Repeat None");
+        }
+    }
+
+    public class RepeatSingleToggleState : ToggleState
+    {
+        public RepeatSingleToggleState()
+        {
+            Icon = Gdk.Pixbuf.LoadFromResource("media-repeat-single.png");
+            Label = Catalog.GetString("Repeat Single");
+        }
+    }
+
+    public class RepeatAllToggleState : ToggleState
+    {
+        public RepeatAllToggleState()
+        {
+            Icon = IconThemeUtils.LoadIcon (16, "media-playlist-repeat");
+            Label = Catalog.GetString("Repeat All");
+        }
+    }
+    
+    public class ShuffleEnabledToggleState : ToggleState
+    {
+        public ShuffleEnabledToggleState()
+        {
+            Icon = IconThemeUtils.LoadIcon (16, "media-playlist-shuffle");
+            Label = Catalog.GetString("Shuffle");
+            MatchActive = true;
+            MatchValue = true;
+        }
+    }
+    
+    public class ShuffleDisabledToggleState : ToggleState
+    {
+        public ShuffleDisabledToggleState()
+        {
+            Icon = Gdk.Pixbuf.LoadFromResource("media-playlist-continuous.png");
+            Label = Catalog.GetString("Continuous");
+            MatchActive = true;
+            MatchValue = false;
+        }
+    }
+}
Index: Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs
===================================================================
--- Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs	(revision 3319)
+++ Core/Banshee.ThickClient/Banshee.Gui/PlaybackActions.cs	(working copy)
@@ -92,7 +92,7 @@
                 new RadioActionEntry ("RepeatSingleAction", null,
                     Catalog.GetString ("Repeat Si_ngle"), null,
                     Catalog.GetString ("Repeat the current playing song"), 2)
-            }, 0, null);
+            }, 0, OnRepeatAction);
 
             actionService.GlobalActions.Add (new ActionEntry [] {
                 new ActionEntry ("PlaybackMenuAction", null,
@@ -206,5 +206,16 @@
                 ? PlaybackShuffleMode.Shuffle
                 : PlaybackShuffleMode.Linear;
         }
+        
+        private void OnRepeatAction (object o, ChangedArgs args)
+        {
+            if (args.Current.Value == 0) {
+                ServiceManager.PlaybackController.RepeatMode = PlaybackRepeatMode.None;
+            } else if (args.Current.Value == 1) {
+                ServiceManager.PlaybackController.RepeatMode = PlaybackRepeatMode.RepeatAll;
+            } else if (args.Current.Value == 2) {
+                ServiceManager.PlaybackController.RepeatMode = PlaybackRepeatMode.RepeatSingle;
+            }
+        }
     }
 }
Index: Core/Banshee.ThickClient/Banshee.Gui.Widgets/PlaybackToggleButtons.cs
===================================================================
--- Core/Banshee.ThickClient/Banshee.Gui.Widgets/PlaybackToggleButtons.cs	(revision 0)
+++ Core/Banshee.ThickClient/Banshee.Gui.Widgets/PlaybackToggleButtons.cs	(revision 0)
@@ -0,0 +1,90 @@
+//
+// PlaybackToggleButtons.cs
+//
+// Author:
+//   Alexander Hixon <hixon alexander mediati org>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Gtk;
+
+using Banshee.Gui;
+using Banshee.Widgets;
+using Banshee.ServiceStack;
+
+namespace Banshee.Gui.Widgets
+{
+    public interface InterfaceToggleButton
+    {
+        string ToggleButtonType {
+            get;
+        }
+    }
+    
+    public class ShuffleToggleButton : MultiStateToggleButton, InterfaceToggleButton
+    {
+        private InterfaceActionService action_service;
+    
+        public ShuffleToggleButton (InterfaceActionService actionService) : base ()
+        {
+            action_service = actionService;
+            
+            this.AddState(typeof(ShuffleDisabledToggleState),
+                    action_service["Playback.ShuffleAction"] as ToggleAction);
+            this.AddState(typeof(ShuffleEnabledToggleState),
+                    action_service["Playback.ShuffleAction"] as ToggleAction);
+            this.Relief = ReliefStyle.None;
+            this.ShowLabel = false;
+        }
+        
+        public string ToggleButtonType
+        {
+            get { return "Shuffle"; }
+        }
+    }
+    
+    public class RepeatToggleButton : MultiStateToggleButton, InterfaceToggleButton
+    {
+        private InterfaceActionService action_service;
+    
+        public RepeatToggleButton (InterfaceActionService actionService) : base ()
+        {
+            action_service = actionService;
+            
+            this.AddState(typeof(RepeatNoneToggleState),
+                action_service["Playback.RepeatNoneAction"] as ToggleAction);
+            this.AddState(typeof(RepeatAllToggleState),
+                action_service["Playback.RepeatAllAction"] as ToggleAction);
+            this.AddState(typeof(RepeatSingleToggleState),
+                action_service["Playback.RepeatSingleAction"] as ToggleAction);
+            this.Relief = ReliefStyle.None;
+            this.ShowLabel = false;
+        }
+        
+        public string ToggleButtonType
+        {
+            get { return "Repeat"; }
+        }
+    }
+}
\ No newline at end of file
Index: Core/Banshee.ThickClient/Makefile.am
===================================================================
--- Core/Banshee.ThickClient/Makefile.am	(revision 3319)
+++ Core/Banshee.ThickClient/Makefile.am	(working copy)
@@ -43,6 +43,7 @@
 	Banshee.Gui.Widgets/ConnectedMessageBar.cs \
 	Banshee.Gui.Widgets/ConnectedSeekSlider.cs \
 	Banshee.Gui.Widgets/ConnectedVolumeButton.cs \
+	Banshee.Gui.Widgets/PlaybackToggleButtons.cs \
 	Banshee.Gui.Widgets/PlaylistMenuItem.cs \
 	Banshee.Gui.Widgets/TrackInfoDisplay.cs \
 	Banshee.Gui.Widgets/UserJobTile.cs \
@@ -59,6 +60,7 @@
 	Banshee.Gui/InterfaceActionService.cs \
 	Banshee.Gui/PlaybackActions.cs \
 	Banshee.Gui/SourceActions.cs \
+	Banshee.Gui/ToggleStates.cs \
 	Banshee.Gui/TrackActions.cs \
 	Banshee.Gui/ViewActions.cs \
 	Banshee.Library.Gui/FileImportSource.cs \
@@ -91,7 +93,12 @@
 	Resources/source-playlist-16.png \
 	Resources/source-playlist-22.png \
 	Resources/source-smart-playlist-16.png \
-	Resources/source-smart-playlist-22.png
+	Resources/source-smart-playlist-22.png \
+	Resources/media-playlist-continuous.png \
+	Resources/media-playlist-shuffle.png \
+	Resources/media-repeat-all.png \
+	Resources/media-repeat-none.png \
+	Resources/media-repeat-single.png
 
 include $(top_srcdir)/build/build.mk
 
Index: Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml
===================================================================
--- Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml	(revision 3319)
+++ Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml	(working copy)
@@ -70,9 +70,9 @@
       <menuitem name="RestartSong" action="RestartSongAction"/>
       <separator/>
       <placeholder name="PlaybackMenuAdditions"/>
-      <!--<menuitem name="RepeatNone" action="RepeatNoneAction"/>
+      <menuitem name="RepeatNone" action="RepeatNoneAction"/>
       <menuitem name="RepeatAll" action="RepeatAllAction"/>
-      <menuitem name="RepeatSingle" action="RepeatSingleAction"/>-->
+      <menuitem name="RepeatSingle" action="RepeatSingleAction"/>
       <separator/>
       <menuitem name="Shuffle" action="ShuffleAction"/>
     </menu>
@@ -92,6 +92,14 @@
       <menuitem name="About" action="AboutAction"/>
     </menu>
   </menubar>
+  
+  <toolbar name="FooterToolbar">
+    <placeholder name="ShuffleToggleAction" />
+    <placeholder name="RepeatToggleAction" />
+    
+    <placeholder name="Statusbar" />
+    <toolitem action="TrackPropertiesAction" />
+  </toolbar>
 
   <popup name="LibraryContextMenu" action="LibraryContextMenuAction">
     <menuitem name="NewPlaylist" action="NewPlaylistAction"/>
Index: Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs
===================================================================
--- Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs	(revision 3319)
+++ Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs	(working copy)
@@ -31,7 +31,7 @@
     public interface ICanonicalPlaybackController : IPlaybackController
     {
         new void First ();
-        new void Next ();
+        new void Next (bool restartAtEnd);
         new void Previous ();
     }
 }
Index: Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
===================================================================
--- Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs	(revision 3319)
+++ Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs	(working copy)
@@ -97,7 +97,11 @@
             switch (args.Event) {
                 case PlayerEngineEvent.EndOfStream:
                     if (!StopWhenFinished) {
-                        Next ();
+                       if (RepeatMode == PlaybackRepeatMode.RepeatSingle) {
+                            QueuePlayTrack ();
+                        } else {
+                            Next ();
+                        }
                     } else {
                         OnStopped ();
                     }
@@ -128,12 +132,17 @@
         
         public void Next ()
         {
+            Next (RepeatMode == PlaybackRepeatMode.RepeatAll);
+        }
+        
+        public void Next (bool restartAtEnd)
+        {
             OnTransition ();
             
             if (Source is IBasicPlaybackController) {
-                ((IBasicPlaybackController)Source).Next ();
+                ((IBasicPlaybackController)Source).Next (restartAtEnd);
             } else {
-                ((ICanonicalPlaybackController)this).Next ();
+                ((ICanonicalPlaybackController)this).Next (restartAtEnd);
             }
         }
         
@@ -155,7 +164,7 @@
             }
         }
         
-        void ICanonicalPlaybackController.Next ()
+        void ICanonicalPlaybackController.Next (bool restartAtEnd)
         {
             TrackInfo tmp_track = CurrentTrack;
 
@@ -170,6 +179,14 @@
                     if (tmp_track != null) {
                         previous_stack.Push (tmp_track);
                     }
+                } else if (restartAtEnd && Source.Count > 0) {
+                    if (tmp_track != null) {
+                        previous_stack.Push (tmp_track);
+                    }
+                    
+                    CurrentTrack = Source.TrackModel[0];
+                    QueuePlayTrack ();
+                    return;
                 } else {
                     return;
                 }
Index: Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs
===================================================================
--- Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs	(revision 3319)
+++ Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs	(working copy)
@@ -31,7 +31,7 @@
     public interface IBasicPlaybackController
     {
         void First ();
-        void Next ();
+        void Next (bool restartAtEnd);
         void Previous ();
     }
 }

Attachment: media-Resources.tar.gz
Description: GNU Zip compressed data



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]