569fb273d603f4457c71db1759732c3c98856bea
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 make logo change color when...

Stefan Schuermans authored 10 years ago

36)     self.widLogoO = self.builder.get_object("LogoO")
37)     self.widLogoG = self.builder.get_object("LogoG")
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

40)       "onFileOpen":         self.onFileOpen,
41)       "onFileExit":         self.onFileExit,
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

49)     }
50)     self.builder.connect_signals(handlers)
Stefan Schuermans reading playlist

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

136)   def updateButtonVisibility(self):
137)     """update the visibility of the buttons based on if playing or not"""
138)     self.widBtnPause.set_visible(self.stPlaying)
139)     self.widBtnPlay.set_visible(not self.stPlaying)
Stefan Schuermans make logo change color when...

Stefan Schuermans authored 10 years ago

140)     self.widLogoO.set_visible(not self.stPlaying)
141)     self.widLogoG.set_visible(self.stPlaying)
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

145)     Gtk.main_quit()
146) 
Stefan Schuermans add menu, implement file open

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

191)     # set position to zero if playing
192)     if self.stPlaying:
193)       self.stPosition = 0
Stefan Schuermans show current playlist item...

Stefan Schuermans authored 10 years ago

194)     # update entry
195)     self.updateEntry()
Stefan Schuermans start making player work -...

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

209) 
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

223)     self.stPlaying = False
224)     self.stPosition = 0 # stop goes back to begin
225)     self.updatePosition()
226)     self.updateButtonVisibility()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

231)     self.stPlaying = False
232)     self.updateButtonVisibility()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

237)     self.stPlaying = True
238)     self.updatePosition()
239)     self.updateButtonVisibility()
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

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

Stefan Schuermans authored 10 years ago

265)     return True
266) 
267) # main application entry point
Stefan Schuermans initial PyGtk window

Stefan Schuermans authored 10 years ago

268) if __name__ == "__main__":
269)   app = SyncGui()
270)   Gtk.main()
271)