59e6b12ec37c677806c4d472118815ffb85f0e06
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

1) #! /usr/bin/env python
2) 
Stefan Schuermans add copyright, remove statu...

Stefan Schuermans authored 10 years ago

3) # BlinkenArea Sync GUI
4) # version 0.1.0 date 2013-11-23
5) # Copyright 2013 Stefan Schuermans <stefan@blinkenarea.org>
6) # Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
7) # a blinkenarea.org project - https://www.blinkenarea.org/
8) 
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

9) import os
10) from gi.repository import Gtk
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

11) import gobject
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

12) import pango
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

13) import sys
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

14) import time
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

15) 
Stefan Schuermans reading playlist

Stefan Schuermans authored 10 years ago

16) import playlist
Stefan Schuermans show current position as h:...

Stefan Schuermans authored 10 years ago

17) import time_fmt
18) 
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

19) scriptdir = os.path.dirname(os.path.abspath(__file__))
20) 
21) class SyncGui:
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

22) 
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

23)   def __init__(self):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

24)     """construct a SyncGui object"""
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

25)     self.builder = Gtk.Builder()
26)     self.builder.add_from_file(scriptdir + "/sync_gui.glade")
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

27)     self.widMainWindow = self.builder.get_object("MainWindow")
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

28)     self.widPlaylistView = self.builder.get_object("PlaylistView")
29)     self.widPlaylistStore = self.builder.get_object("PlaylistStore")
30)     self.widPosition = self.builder.get_object("Position")
31)     self.widPositionScale = self.builder.get_object("PositionScale")
32)     self.widPositionAt = self.builder.get_object("PositionAt")
33)     self.widPositionRemaining = self.builder.get_object("PositionRemaining")
34)     self.widBtnPause = self.builder.get_object("Pause")
35)     self.widBtnPlay = self.builder.get_object("Play")
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

36)     handlers = {
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

37)       "onDestroy":          self.onDestroy,
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

38)       "onFileOpen":         self.onFileOpen,
39)       "onFileExit":         self.onFileExit,
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

40)       "onPlaylistDblClick": self.onPlaylistDblClick,
41)       "onNewPosition":      self.onNewPosition,
42)       "onPrevious":         self.onPrevious,
43)       "onStop":             self.onStop,
44)       "onPause":            self.onPause,
45)       "onPlay":             self.onPlay,
46)       "onNext":             self.onNext,
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

47)     }
48)     self.builder.connect_signals(handlers)
Stefan Schuermans reading playlist

Stefan Schuermans authored 10 years ago

49)     self.playlist = playlist.Playlist()
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

50)     if len(sys.argv) >= 2: # load initial playlist from command line
51)       self.playlist.read(sys.argv[1])
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

52)     self.playlist.update(self.widPlaylistStore)
53)     self.stEntryIdx = -1 # no entry selected
54)     self.stName = "" # no current entry name
55)     self.stDuration = 0 # current entry has zero size
56)     self.stPosition = 0 # at begin of current entry
57)     self.stPlaying = False # not playing
58)     gobject.timeout_add(10, self.onTimer10ms)
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

59)     self.updateEntry()
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

60)     self.updateButtonVisibility()
Stefan Schuermans show current position as h:...

Stefan Schuermans authored 10 years ago

61) 
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

62)   def showPosition(self):
63)     """update the position texts next to the position slider"""
64)     # format current time and remaining time
65)     posAt = time_fmt.sec2str(self.stPosition)
66)     posRemaining = time_fmt.sec2str(self.stDuration - self.stPosition)
67)     self.widPositionAt.set_text(posAt)
68)     self.widPositionRemaining.set_text(posRemaining)
69) 
70)   def updatePositionState(self):
71)     """update the position in the state, but not the slider"""
72)     # calculate (virtual) start time of playing
73)     # i.e. the time the playing would have had started to arrive at the
74)     # current position now if it had played continuosly
75)     self.stPlayStart = time.time() - self.stPosition
76)     # update position texts
77)     self.showPosition()
78) 
79)   def updatePosition(self):
80)     """update the position including the position slider"""
81)     # update GUI slider
82)     self.widPositionScale.set_value(self.stPosition)
83)     # update position state
84)     self.updatePositionState()
85) 
86)   def updateDuration(self):
87)     """update the duration (i.e. range for the slider) based on the current
88)        playlist entry"""
89)     # get duration of new playlist entry
90)     self.stDuration = 0
91)     if self.stEntryIdx >= 0:
92)       entry = self.playlist.entries[self.stEntryIdx]
93)       if entry["type"] == "normal":
94)         self.stDuration = entry["duration"]
95)     # set position to begin
96)     self.stPosition = 0
97)     # update value range
98)     self.widPosition.set_upper(self.stDuration)
99)     # update position of slider
100)     self.updatePosition()
101) 
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

102)   def updateEntry(self):
103)     """update current entry of playlist and duration, position, ..."""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

104)     # clear selection of playlist
105)     sel = self.widPlaylistView.get_selection()
106)     if sel:
107)       sel.unselect_all()
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

108)     # sanity check for entry index
109)     if self.stEntryIdx < -1 or self.stEntryIdx >= len(self.playlist.entries):
110)       self.stEntryIdx = -1
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

111)     # get name of current entry
112)     self.stName = ""
113)     if self.stEntryIdx >= 0 and \
114)        self.playlist.entries[self.stEntryIdx]["type"] == "normal":
115)       self.stName = self.playlist.entries[self.stEntryIdx]["name"]
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

116)     # make current entry bold, all others non-bold
117)     def update(model, path, it, user_data):
118)       (idx,) = model.get(it, 0)
119)       if idx == self.stEntryIdx:
120)         weight = pango.WEIGHT_BOLD
121)       else:
122)         weight = pango.WEIGHT_NORMAL
123)       model.set(it, 1, weight)
124)     self.widPlaylistStore.foreach(update, None)
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

125)     # playing and (no entry or stop entry)
126)     # -> stop playing and update button visibility
127)     if self.stPlaying and (self.stEntryIdx < 0 or \
128)        self.playlist.entries[self.stEntryIdx]["type"] == "stop"):
129)       self.stPlaying = False
130)       self.updateButtonVisibility()
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

131)     # update duration, position, ...
132)     self.updateDuration()
133) 
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

134)   def updateButtonVisibility(self):
135)     """update the visibility of the buttons based on if playing or not"""
136)     self.widBtnPause.set_visible(self.stPlaying)
137)     self.widBtnPlay.set_visible(not self.stPlaying)
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

138) 
139)   def onDestroy(self, widget):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

140)     """window will be destroyed"""
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

141)     Gtk.main_quit()
142) 
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

143)   def onFileOpen(self, widget):
144)     """File Open clicked in menu"""
145)     #print("DEBUG sync_gui File Open")
146)     # run file chooser dialog
147)     dialog = Gtk.FileChooserDialog("BlinkenArea Sync GUI - File Open..",
148)                                    self.widMainWindow,
149)                                    Gtk.FileChooserAction.OPEN,
150)                                    (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
151)                                     Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
152)     dialog.set_default_response(Gtk.ResponseType.OK)
153)     filt = Gtk.FileFilter()
154)     filt.set_name("All files")
155)     filt.add_pattern("*")
156)     dialog.add_filter(filt)
157)     response = dialog.run()
158)     if response == Gtk.ResponseType.OK:
159)       # dialog closed with OK -> load new playlist
160)       filename = dialog.get_filename()
161)       self.playlist.read(filename)
162)       self.playlist.update(self.widPlaylistStore)
163)       self.stEntryIdx = -1 # no entry selected
164)       self.stPlaying = False # not playing
165)       self.updateEntry()
166)       self.updateButtonVisibility()
167)     # cleanup
168)     dialog.destroy()
169) 
170)   def onFileExit(self, widget):
171)     """File Exit clicked in menu"""
172)     #print("DEBUG sync_gui File Exit")
173)     Gtk.main_quit()
174) 
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

175)   def onPlaylistDblClick(self, widget, row, col):
176)     """playlist entry has been double-clicked"""
177)     # get index of selected entry
178)     idx = -1
179)     sel = self.widPlaylistView.get_selection()
180)     if sel is not None:
181)       (model, it) = sel.get_selected()
182)       if it is not None:
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

183)         (idx,) = model.get(it, 0)
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

184)     #print("DEBUG sync_gui playlist double-click idx=%d" % (idx))
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

185)     # update playlist entry
186)     self.stEntryIdx = idx
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

187)     # set position to zero if playing
188)     if self.stPlaying:
189)       self.stPosition = 0
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

190)     # update entry
191)     self.updateEntry()
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

192) 
Stefan Schuermans show current position as h:...

Stefan Schuermans authored 10 years ago

193)   def onNewPosition(self, widget, scroll, value):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

194)     """slider has been moved to a new position"""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

195)     #print("DEBUG sync_gui new position " + str(value));
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

196)     # clamp position to valid range
197)     if value < 0:
198)       value = 0
199)     if value > self.stDuration:
200)       value = self.stDuration
201)     # update current position - and play start time if playing
202)     self.stPosition = value
203)     # update position state (do not touch the slider)
204)     self.updatePositionState()
Stefan Schuermans show current position as h:...

Stefan Schuermans authored 10 years ago

205) 
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

206)   def onPrevious(self, widget):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

207)     """previous button as been pressed"""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

208)     #print("DEBUG sync_gui previous")
209)     # go to begin of previous entry (with wrap around)
210)     self.stPosition = 0
211)     self.stEntryIdx = self.stEntryIdx - 1
212)     if self.stEntryIdx < 0:
213)       self.stEntryIdx = len(self.playlist.entries) - 1
214)     self.updateEntry()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

215) 
216)   def onStop(self, widget):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

217)     """stop button has been pressed"""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

218)     #print("DEBUG sync_gui stop")
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

219)     self.stPlaying = False
220)     self.stPosition = 0 # stop goes back to begin
221)     self.updatePosition()
222)     self.updateButtonVisibility()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

223) 
224)   def onPause(self, widget):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

225)     """pause button has been pressed"""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

226)     #print("DEBUG sync_gui pause")
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

227)     self.stPlaying = False
228)     self.updateButtonVisibility()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

229) 
230)   def onPlay(self, widget):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

231)     """play button has been pressed"""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

232)     #print("DEBUG sync_gui play")
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

233)     self.stPlaying = True
234)     self.updatePosition()
235)     self.updateButtonVisibility()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

236) 
237)   def onNext(self, widget):
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

238)     """next button has been pressed"""
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

239)     #print("DEBUG sync_gui next")
240)     # go to begin of next entry (with wrap around)
241)     self.stPosition = 0
242)     self.stEntryIdx = self.stEntryIdx + 1
243)     if self.stEntryIdx >= len(self.playlist.entries):
244)       self.stEntryIdx = 0
245)     self.updateEntry()
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

246) 
247)   def onTimer10ms(self):
248)     """timer callback, every 10ms"""
249)     # update position if playing
250)     if self.stPlaying:
251)       self.stPosition = time.time() - self.stPlayStart
Stefan Schuermans remove forward and backward...

Stefan Schuermans authored 10 years ago

252)       if self.stPosition >= self.stDuration:
253)         # end of entry reached --> go to begin of next entry (with wrap around)
254)         self.stPosition = 0
255)         self.stEntryIdx = self.stEntryIdx + 1
256)         if self.stEntryIdx >= len(self.playlist.entries):
257)           self.stEntryIdx = 0
258)         self.updateEntry()
259)       else:
260)         self.updatePosition()
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

261)     return True
262) 
263) # main application entry point
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

264) if __name__ == "__main__":
265)   app = SyncGui()
266)   Gtk.main()
267)