Commits

Damián Nohales committed 97ee06b

Seekbar and time info, some refactors on widgets fields.

Comments (0)

Files changed (4)

data/main_window.ui

       </object>
     </child>
     <child>
+      <object class="GtkImageMenuItem" id="fullscreen_menuitem">
+        <property name="label">gtk-fullscreen</property>
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="use_action_appearance">False</property>
+        <property name="use_underline">True</property>
+        <property name="use_stock">True</property>
+        <signal name="activate" handler="on_toggle_fullscreen" swapped="no"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkSeparatorMenuItem" id="menuitem1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+    </child>
+    <child>
       <object class="GtkImageMenuItem" id="chekupdatemenuitem">
         <property name="label" translatable="yes">Check for Updates</property>
         <property name="visible">True</property>
       </object>
     </child>
     <child>
-      <object class="GtkSeparatorMenuItem" id="menuitem1">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-      </object>
-    </child>
-    <child>
       <object class="GtkImageMenuItem" id="quitmenuitem">
         <property name="label">gtk-quit</property>
         <property name="visible">True</property>
     <property name="default_width">700</property>
     <property name="default_height">350</property>
     <property name="icon">gsharkdown_64.png</property>
+    <signal name="delete-event" handler="on_window_close" swapped="no"/>
     <child>
       <object class="GtkVBox" id="vbox1">
         <property name="visible">True</property>
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="toolbar_style">both-horiz</property>
+            <property name="show_arrow">False</property>
             <property name="icon_size_set">True</property>
             <child>
               <object class="GtkToolItem" id="toolbutton1">
               </packing>
             </child>
             <child>
-              <object class="GtkToolItem" id="toolbutton_volume">
+              <object class="GtkToolItem" id="toolbutton5">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="use_action_appearance">False</property>
               </object>
               <packing>
                 <property name="expand">True</property>
-                <property name="homogeneous">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkToggleToolButton" id="fullscreen_button">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="use_action_appearance">False</property>
-                <property name="label" translatable="yes">Fullscreen</property>
-                <property name="use_underline">True</property>
-                <property name="stock_id">gtk-fullscreen</property>
-                <signal name="toggled" handler="on_toggle_fullscreen" swapped="no"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">True</property>
               </packing>
             </child>
             <child>
                 <property name="can_focus">False</property>
                 <property name="tooltip_text" translatable="yes">Menu</property>
                 <property name="use_action_appearance">False</property>
-                <property name="label" translatable="yes">Settings</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes">Menu</property>
                 <property name="use_underline">True</property>
                 <property name="stock_id">gtk-properties</property>
                 <signal name="clicked" handler="show_prefs_menu" swapped="no"/>
               </object>
               <packing>
                 <property name="expand">False</property>
-                <property name="homogeneous">True</property>
               </packing>
             </child>
           </object>
                         <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                         <property name="use_action_appearance">False</property>
-                        <property name="image">toolbutton_play</property>
+                        <property name="image">widget_image_play</property>
                         <signal name="clicked" handler="on_play_selected" swapped="no"/>
                       </object>
                       <packing>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkHScale" id="hscale1">
+                      <object class="GtkHScale" id="seekbar">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
+                        <property name="tooltip_text" translatable="yes">Seek is planned for
+future version</property>
                         <property name="draw_value">False</property>
+                        <signal name="change-value" handler="on_seekbar_change_value" swapped="no"/>
                       </object>
                       <packing>
                         <property name="expand">True</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="label2">
+                      <object class="GtkLabel" id="label_player_time">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="label" translatable="yes">{played} / {time}</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="button7">
+                      <object class="GtkButton" id="button_love">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="toolbutton_lyrics">
+                      <object class="GtkButton" id="button_lyrics">
                         <property name="label" translatable="yes">Lyrics</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
       </object>
     </child>
   </object>
-  <object class="GtkImage" id="toolbutton_play">
+  <object class="GtkImage" id="widget_image_play">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="pixel_size">22</property>
     <property name="icon_name">media-playback-start</property>
   </object>
+  <object class="GtkImage" id="widget_image_stop">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="pixel_size">22</property>
+    <property name="icon_name">media-playback-stop</property>
+  </object>
 </interface>
 
         self.working = None
         self.playing = None
-        # just to prevend scrobbeling more then once for 
-        # track.
+        # just to prevend scrobbeling more then once for track.
         self.scrobbled = 0
-        # Download dictionary in form Filename : Thread
         self.last_iter = None
         self.windowstate = 1
         self.current_song = None
         self.play_thread = None
         self.notify_timeout_id = None
+        self.player_state_timeout_id = None
+        self.is_buffering = False
 
         init_thread = InitThread(self)
         init_thread.start()
-
-        # Main window initialization
+        
+        # GtkBuilder initialization
         builder = gtk.Builder()
         builder.set_translation_domain(env().APP)
         builder.add_from_file('%s/data/main_window.ui' % env().BASEPATH)
+        
+        # Main window and widgets initialization
         self.window = builder.get_object('mainwindow')
-        self.window.connect('delete-event', self.on_window_close)
-        self.play_button = builder.get_object('toolbutton_play')
-        self.ff_button = builder.get_object('toolbutton_play_next')
-        self.prev_button = builder.get_object('toolbutton_play_previous')
-        self.lyrics_button = builder.get_object('toolbutton_lyrics')
+        self.mainmenu = builder.get_object('mainmenu')
+        
+        self.button_play = builder.get_object('button_play')
+        self.widget_image_play = builder.get_object('widget_image_play')
+        self.widget_image_stop = builder.get_object('widget_image_stop')
+        self.widget_image_buffering = gtk.Image()
+        self.widget_image_buffering.set_from_file('%s/data/buffering.gif' % env().BASEPATH)
+        self.widget_image_buffering.set_pixel_size(22)
+        
+        self.label_player_time = builder.get_object('label_player_time')
+        self.seekbar = builder.get_object('seekbar')
+        self.button_lyrics = builder.get_object('button_lyrics')
+        self.button_love = builder.get_object('button_love')
+        self.button_songinfo = builder.get_object('button_songinfo')
         self.songinfo = builder.get_object('songinfo')
-        self.songinfo.set_text("")
-        self.prefsmenu = builder.get_object('mainmenu')
-        self.lovebutton = builder.get_object('toolbutton3')
-        repeat_button = builder.get_object('togglebutton_repeat')
-        repeat_button.set_active(int(config()['repeat_playlist']))
-        shuffle_button = builder.get_object('togglebutton_shuffle')
-        shuffle_button.set_active(int(config()['shuffle_playlist']))
+        
+        button_repeat = builder.get_object('togglebutton_repeat')
+        button_repeat.set_active(int(config()['repeat_playlist'])) 
+        button_shuffle = builder.get_object('togglebutton_shuffle')
+        button_shuffle.set_active(int(config()['shuffle_playlist']))
+        
         self.panes = builder.get_object('notebook1')
         self.playview_pane_label = builder.get_object('togglebutton1')
         self.downloads_pane_label = builder.get_object('togglebutton2')
+        
+        self.entry_search = builder.get_object('toolentry_search')
+        
+        # GStreamer player initialization
         self.player = gst.element_factory_make("playbin", "player")
 
         # Completition configuration
-        self.entry = builder.get_object('toolentry_search')
         completition = gtk.EntryCompletion()
         comp_store = gtk.ListStore(str)
         completition.set_model(comp_store)
             comp_store.append([item])
         completition.set_minimum_key_length(1)
         completition.set_text_column(0)
-        self.entry.set_completion(completition)
+        self.entry_search.set_completion(completition)
 
         # Results List definition
         self.result = SearchResultList(builder.get_object('list_results'))
         self.window.show_all()
         
         self.on_playlist_row_changed(self.playlist.get_model())
+        self.set_playing_song(None)
 
 
     def on_init_thread_success(self):
         else:
             pass
 
-    def on_toggle_fullscreen(self, button, data = None):
+    def on_toggle_fullscreen(self, menuitem, data = None):
         """docstring for on_toggle_fullscreen"""
-        if button.get_active():
+        if menuitem.get_label() == "gtk-fullscreen":
             self.window.fullscreen()
+            menuitem.set_label("gtk-leave-fullscreen")
         else:
             self.window.unfullscreen()
+            menuitem.set_label("gtk-fullscreen")
 
     def on_filter_changed(self, entry, data = None):
         print entry.get_text()
         return self.playlist.get_song(index)
 
     def show_prefs_menu(self, button, data = None):
-        self.prefsmenu.popup(None, None, None, 0, 0)
+        self.mainmenu.popup(None, None, None, 0, 0)
 
     def load_saved_playlist(self, path):
         """
 
     def get_playing_iter(self):
         return self.playlist.get_song_iter(self.get_playing_song())
-
+    
+    def on_player_message(self, bus, message):
+        if message.type == gst.MESSAGE_BUFFERING and not self.is_buffering:
+            self.button_play.set_image(self.widget_image_buffering)
+            self.is_buffering = True
+        elif message.type == gst.MESSAGE_EOS:
+            self.app.play_next()
+        elif message.type == gst.MESSAGE_ASYNC_DONE:
+            self.is_buffering = False
+            self.button_play.set_image(self.widget_image_stop)
+            
+    def on_player_idle(self):
+        try:
+            duration = self.player.query_duration(gst.FORMAT_TIME)[0] / gst.SECOND
+            cur = self.player.query_position(gst.FORMAT_TIME)[0] / gst.SECOND
+            self.seekbar.set_range(0, duration)
+            self.seekbar.set_value(cur)
+            self.label_player_time.set_text("%s / %s" % (Song.format_time(cur), Song.format_time(duration)))
+        except Exception, e:
+            pass
+        
+        return True
+    
+    def on_seekbar_change_value(self, range, scroll, value):
+        return True
+    
     def get_playing_song(self):
         return self.playlist.get_playing_song()
 
         Updates some labels and icons when a song is playing
         """
         self.playlist.set_playing_song(song)
+        self.seekbar.set_value(0)
+        self.label_player_time.set_text("- / -")
+        self.player.set_state(gst.STATE_NULL)
 
         if song != None:
-            self.staticon.change_status_playing()
+            self.is_buffering = True
 
             play_stop_image = gtk.Image()
             play_stop_image.set_from_stock(gtk.STOCK_MEDIA_STOP, gtk.ICON_SIZE_MENU)
             self.staticon.change_playbutton(play_stop_image)
-            self.play_button.set_from_icon_name("media-playback-stop", 22)
+            self.staticon.change_status_playing()
+            
+            self.button_play.set_image(self.widget_image_buffering)
+            
+            self.button_songinfo.set_sensitive(True)
+            self.button_lyrics.set_sensitive(True)
+            self.button_love.set_sensitive(True)
+            
             self.scrobbled = 0
 
             self.songinfo.set_markup(
                 if self.notify_timeout_id != None:
                     gobject.source_remove(self.notify_timeout_id)
                 self.notify_timeout_id = gobject.timeout_add(1000, self.show_playing_song_notification)
-
-            self.player.set_state(gst.STATE_NULL)
+                
+            if self.player_state_timeout_id == None:
+                self.player_state_timeout_id = gobject.timeout_add(500, self.on_player_idle)
 
             if self.play_thread != None:
                 # Avoid the current song streaming
         else:
             if self.play_thread != None:
                 self.play_thread.stop()
+                
+            if self.notify_timeout_id != None:
+                gobject.source_remove(self.notify_timeout_id)
+                self.notify_timeout_id = None
+                
+            if self.player_state_timeout_id != None:
+                gobject.source_remove(self.player_state_timeout_id)
+                self.player_state_timeout_id = None
 
             self.staticon.change_status_stopped()
             play_stop_image = gtk.Image()
             play_stop_image.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)
             self.staticon.change_playbutton(play_stop_image)
-            self.player.set_state(gst.STATE_NULL)
-            self.play_button.set_from_icon_name("media-playback-start", 22)
+            
+            self.button_play.set_image(self.widget_image_play)
             self.songinfo.set_markup("")
+            
+            self.button_songinfo.set_sensitive(False)
+            self.button_lyrics.set_sensitive(False)
+            self.button_love.set_sensitive(False)
 
     def show_playing_song_notification(self):
         song = self.get_playing_song()
     def get_duration(self):
         return self.data['EstimateDuration']
     
-    def get_duration_human_readable(self):
-        duration = float(self.get_duration())
+    @staticmethod
+    def format_time(dur):
+        duration = float(dur)
         mins = math.floor(duration / 60)
         secs = duration % 60
         
         return "%02d:%02d" % (mins, secs)
     
+    def get_duration_human_readable(self):
+        return Song.format_time(self.get_duration()) 
+    
     def get_last_error(self):
         return self.last_error
     
         bus = self.app.player.get_bus()
         bus.enable_sync_message_emission()
         bus.add_signal_watch()
-# I will leave this commented out just till it's confirmed that
-# it's not needed anymore.
-#        bus.connect("message", self.on_message_cb)
-        bus.connect('message::eos', self.on_stopped)
-
-#    def on_message_cb(self, bus, message):
-#        if message.type == gst.MESSAGE_STATE_CHANGED:
-#            old, new, pending = message.parse_state_changed()
-#            self.update_buttons(new)
-#        return gst.BUS_PASS
-
-    def on_stopped(self, config, widget = None, data = None):
-        gobject.idle_add(self.app.play_next)
+        bus.connect('message', self.app.on_player_message)
 
     def stop(self):
         self._stop.set()
         """
         if what in ['Stop', 'Play', 'Next', 'Previous']:
             if what == 'Stop':
-                gobject.idle_add(self.app.on_play_selected, self.app.play_button)
+                gobject.idle_add(self.app.on_play_selected, self.app.button_play)
             elif what == 'Play':
-                gobject.idle_add(self.app.on_play_selected, self.app.play_button)
+                gobject.idle_add(self.app.on_play_selected, self.app.button_play)
             elif what == 'Next':
                 gobject.idle_add(self.app.on_play_next)
             elif what == 'Previous':
         self.app = app
         self.query = query
         self.type = type
-        self.app.entry.set_sensitive(False)
+        self.app.entry_search.set_sensitive(False)
 
     def run(self):
         try:
             print e.args
 
     def fill_results(self, results):
-        self.app.entry.set_sensitive(True)
+        self.app.entry_search.set_sensitive(True)
         self.app.result.clear()
         if results:
             for song_data in results:
         threading.Thread.__init__(self)
         self.app = app
         self.song = song
-        self.app.lyrics_button.set_sensitive(False)
-        self.app.lyrics_button.set_label(_("Loading lyrics..."))
+        self.app.button_lyrics.set_sensitive(False)
+        self.app.button_lyrics.set_label(_("Loading lyrics..."))
 
     def run(self):
         lyrics = lyrdblib.search(self.song.get_artist(), self.song.get_title())
         gobject.idle_add(self.open_viewer, lyrics)
 
     def open_viewer(self, lyrics):
-        self.app.lyrics_button.set_sensitive(True)
-        self.app.lyrics_button.set_label(_("Lyrics"))
+        self.app.button_lyrics.set_sensitive(True)
+        self.app.button_lyrics.set_label(_("Lyrics"))
         if "ERROR:" in lyrics:
             error = guihelpers.ErrorMessage(self.app.window, lyrics)
             error.run()