_ARTIST_FIELDS = ['id', 'name', 'image']
_ALBUM_FIELDS = ['id', 'name', 'image', 'artist_name', 'artist_id', 'license_url']
-_TRACK_FIELDS = ['id', 'name', 'image', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration']
+_TRACK_FIELDS = ['id', 'name', 'image', 'artist_id', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration']
_RADIO_FIELDS = ['id', 'name', 'idstr', 'image']
class LazyQuery(object):
self.ID = int(ID)
self.name = None
self.image = None
+ self.artist_id = None
self.artist_name = None
self.album_name = None
self.album_id = None
return _OGGURL%(self.ID)
def _needs_load(self):
- return self._needs_load_impl('name', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration')
+ return self._needs_load_impl('name', 'artist_name', 'artist_id', 'album_name', 'album_id', 'numalbum', 'duration')
def _set_from(self, other):
- return self._set_from_impl(other, 'name', 'image', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration')
+ return self._set_from_impl(other, 'name', 'image', 'artist_name', 'artist_id', 'album_name', 'album_id', 'numalbum', 'duration')
class Radio(LazyQuery):
def __init__(self, ID, json=None):
pass
def _geturl(self, url):
- #print "*** %s" % (url)
+ print "*** %s" % (url)
Query._ratelimit()
try:
f = urllib.urlopen(url)
'params' : 'artist_id=%d',
'constructor' : Artist
},
+ 'artist_list' : {
+ 'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/artist/json/?',
+ 'params' : 'artist_id=%s',
+ 'constructor' : Album
+ },
'album' : {
'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
'params' : 'album_id=%d',
'constructor' : Album
},
+ 'album_list' : {
+ 'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
+ 'params' : 'album_id=%s',
+ 'constructor' : Album
+ },
'albums' : {
'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
'params' : 'artist_id=%d',
'params' : 'id=%d',
'constructor' : Track
},
+ 'track_list' : {
+ 'url' : _GET2+'+'.join(_TRACK_FIELDS)+'/track/json/track_album+album_artist?',
+ 'params' : 'id=%s',
+ 'constructor' : Track
+ },
'tracks' : {
'url' : _GET2+'+'.join(_TRACK_FIELDS)+'/track/json/track_album+album_artist?',
'params' : 'order=numalbum_asc&album_id=%d',
old._set_from(item)
else:
cache[item.ID] = item
+ if isinstance(item, Artist) and item.albums:
+ for album in item.albums:
+ _update_cache(_albums, album)
+ elif isinstance(item, Album) and item.tracks:
+ for track in item.tracks:
+ _update_cache(_tracks, track)
def get_artist(artist_id):
"""Returns: Artist"""
a = a[0]
return a
-def get_albums(artist_id):
+def get_artists(artist_ids):
+ """Returns: [Artist]"""
+ assert(isinstance(artist_ids, list))
+ found = []
+ lookup = []
+ for artist_id in artist_ids:
+ a = _artists.get(artist_id, None)
+ if not a:
+ lookup.append(artist_id)
+ else:
+ found.append(a)
+ if lookup:
+ q = GetQuery('artist_list', '+'.join(str(x) for x in lookup))
+ a = q.execute()
+ if not a:
+ raise JamendoAPIException(str(q))
+ _update_cache(_artists, a)
+ lookup = a
+ return found + lookup
+
+def get_album_list(album_ids):
"""Returns: [Album]"""
+ assert(isinstance(album_ids, list))
+ found = []
+ lookup = []
+ for album_id in album_ids:
+ a = _albums.get(album_id, None)
+ if not a:
+ lookup.append(album_id)
+ else:
+ found.append(a)
+ if lookup:
+ q = GetQuery('album_list', '+'.join(str(x) for x in lookup))
+ a = q.execute()
+ if not a:
+ raise JamendoAPIException(str(q))
+ _update_cache(_albums, a)
+ lookup = a
+ return found + lookup
+
+def get_albums(artist_id):
+ """Returns: [Album]
+ Parameter can either be an artist_id or a list of album ids.
+ """
+ if isinstance(artist_id, list):
+ return get_album_list(artist_id)
+ a = _artists.get(artist_id, None)
+ if a and a.albums:
+ return a.albums
+
q = GetQuery('albums', artist_id)
a = q.execute()
if not a:
a = a[0]
return a
-def get_tracks(album_id):
+def get_track_list(track_ids):
"""Returns: [Track]"""
+ assert(isinstance(track_ids, list))
+ found = []
+ lookup = []
+ for track_id in track_ids:
+ a = _tracks.get(track_id, None)
+ if not a:
+ lookup.append(track_id)
+ else:
+ found.append(a)
+ if lookup:
+ q = GetQuery('track_list', '+'.join(str(x) for x in lookup))
+ a = q.execute()
+ if not a:
+ raise JamendoAPIException(str(q))
+ _update_cache(_tracks, a)
+ lookup = a
+ return found + lookup
+
+def get_tracks(album_id):
+ """Returns: [Track]
+ Parameter can either be an album_id or a list of track ids.
+ """
+ if isinstance(album_id, list):
+ return get_track_list(album_id)
+ a = _albums.get(album_id, None)
+ if a and a.tracks:
+ return a.tracks
+
q = GetQuery('tracks', album_id)
a = q.execute()
if not a:
def _artist_loader(self):
if self._needs_load():
artist = get_artist(self.ID)
+ artist.albums = get_albums(self.ID)
self._set_from(artist)
Artist.load = _artist_loader
import sys
LOG_FILENAME = '/tmp/jamaendo.log'
-LOG_LEVEL = logging.INFO
+LOG_LEVEL = logging.DEBUG
+
+#
+logging.basicConfig(filename=LOG_FILENAME, level=LOG_LEVEL, format="%(name)-15s: [%(lineno)4d] %(levelname)-8s %(message)s")
-logging.basicConfig(filename=LOG_FILENAME,level=LOG_LEVEL, format="%(name)-15s: [%(lineno)4d] %(levelname)-8s %(message)s")
def get_track_id(self, path):
treeiter = self.__store.get_iter(path)
+ _, _, _id = self.__store.get(treeiter, 0, 1, 2)
+ return _id
+
+class RadioList(gtk.TreeView):
+ def __init__(self):
+ gtk.TreeView.__init__(self)
+ self.__store = gtk.ListStore(str, int)
+ self.set_model(self.__store)
+
+ col = gtk.TreeViewColumn('Name')
+ self.append_column(col)
+ cell = gtk.CellRendererText()
+ col.pack_start(cell, True)
+ col.add_attribute(cell, 'text', 0)
+
+ self.set_search_column(0)
+ col.set_sort_column_id(0)
+
+ def add_radio(self, radio):
+ self.__store.append([self.radio_name(radio), radio.ID])
+
+ def get_radio_id(self, path):
+ treeiter = self.__store.get_iter(path)
_, _id = self.__store.get(treeiter, 0, 1)
return _id
+
+ def radio_name(self, radio):
+ if radio.idstr:
+ return radio.idstr.capitalize()
+ elif radio.name:
+ return radio.name
+ else:
+ return "Radio #%s" % (radio.ID)
msg)
banner.set_timeout(3000)
- for item in settings.favorites:
- try:
- if isinstance(item, tuple) and len(item) == 2:
- ftype, fid = item
- if ftype == 'album':
- add_album(fid, lambda: jamaendo.get_album(fid))
-
- except jamaendo.JamendoAPIException, e:
- log.exception("jamaendo.get_album(%s)"%(fid))
+ favorite_albums = [f[1] for f in settings.favorites if isinstance(f, tuple) and len(f) == 2 and f[0] == 'album' and f[1] not in self.idmap]
+ try:
+ for album in jamaendo.get_albums(favorite_albums):
+ add_album(album.ID, lambda: album)
+
+ except jamaendo.JamendoAPIException, e:
+ log.exception("jamaendo.get_albums(%s)"%(favorite_albums))
self.add(self.panarea)
self.create_menu()
def create_menu(self):
- def on_player():
+ def on_player(*args):
from playerwindow import open_playerwindow
open_playerwindow()
self.menu = hildon.AppMenu()
entry = self.playlist.next()
self.backend.play_url('mp3', entry.mp3_url())
log.debug("playing %s", entry)
+ postoffice.notify('play', entry)
def pause(self):
self.backend.pause()
+ postoffice.notify('pause', self.playlist.current())
def stop(self):
self.backend.stop()
+ postoffice.notify('stop', self.playlist.current())
def playing(self):
return self.backend.playing()
entry = self.playlist.next()
self.backend.play_url('mp3', entry.mp3_url())
log.debug("playing %s", entry)
+ postoffice.notify('next', entry)
else:
self.stop()
entry = self.playlist.prev()
self.backend.play_url('mp3', entry.mp3_url())
log.debug("playing %s", entry)
+ postoffice.notify('prev', entry)
def _on_eos(self):
log.debug("EOS!")
import gtk
import gobject
import hildon
+import util
+import pango
from settings import settings
from postoffice import postoffice
from player import Playlist, the_player
import logging
+import cgi
+
+from songposition import SongPosition
log = logging.getLogger(__name__)
vbox = gtk.VBox()
- hbox = gtk.HBox()
+ hbox = gtk.HBox(False, 8)
self.cover = gtk.Image()
- self.cover.set_from_stock(gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
+ tmp = util.find_resource('album.png')
+ if tmp:
+ self.cover.set_from_file(tmp)
vbox2 = gtk.VBox()
self.playlist_pos = gtk.Label()
+ self.playlist_pos.set_alignment(1.0,0)
self.track = gtk.Label()
- self.progress = hildon.GtkHScale()
- self.progress.set_draw_value(False)
- self.progress.set_range(0.0, 1.0)
+ self.track.set_alignment(0,0)
+ self.track.set_ellipsize(pango.ELLIPSIZE_END)
self.artist = gtk.Label()
+ self.artist.set_alignment(0,0)
+ self.artist.set_ellipsize(pango.ELLIPSIZE_END)
self.album = gtk.Label()
+ self.album.set_alignment(0,0)
+ self.album.set_ellipsize(pango.ELLIPSIZE_END)
+ self.progress = SongPosition()
self.set_labels('', '', '', 0, 0)
self._position_timer = None
- vbox2.pack_start(self.track, True)
- vbox2.pack_start(self.artist, False)
- vbox2.pack_start(self.album, False)
vbox2.pack_start(self.playlist_pos, False)
- vbox2.pack_start(self.progress, False)
+ vbox2.pack_start(self.track, True)
+ vbox2.pack_start(self.artist, True)
+ vbox2.pack_start(self.album, True)
- hbox.pack_start(self.cover, True, True, 0)
+ hbox.pack_start(self.cover, False, True, 0)
hbox.pack_start(vbox2, True, True, 0)
vbox.pack_start(hbox, True, True, 0)
btns = gtk.HButtonBox()
btns.set_property('layout-style', gtk.BUTTONBOX_SPREAD)
- vbox.pack_end(btns, False, True, 0)
+ vbox.pack_start(btns, False, True, 0)
+
+ vbox.pack_start(self.progress, False)
self.add_stock_button(btns, gtk.STOCK_MEDIA_PREVIOUS, self.on_prev)
self.add_play_button(btns)
self.add_stock_button(btns, gtk.STOCK_MEDIA_STOP, self.on_stop)
self.add_stock_button(btns, gtk.STOCK_MEDIA_NEXT, self.on_next)
- self.volume = hildon.VVolumebar()
- self.volume.set_property('can-focus', False)
- self.volume.connect('level_changed', self.volume_changed_hildon)
- self.volume.connect('mute_toggled', self.mute_toggled)
- #self.__gui_root.main_window.connect( 'key-press-event',
- # self.on_key_press )
- hbox.pack_start(self.volume, False)
+ #self.volume = hildon.VVolumebar()
+ #self.volume.set_property('can-focus', False)
+ #self.volume.connect('level_changed', self.volume_changed_hildon)
+ #self.volume.connect('mute_toggled', self.mute_toggled)
+ #hbox.pack_start(self.volume, False)
self.add(vbox)
postoffice.connect('album-cover', self, self.set_album_cover)
+ postoffice.connect(['next', 'prev', 'play', 'pause', 'stop'], self, self.on_state_changed)
#print "Created player window, playlist: %s" % (self.playlist)
+ self.on_state_changed()
+
+ self.create_menu()
+
+ def create_menu(self):
+ self.menu = hildon.AppMenu()
+
+ def to_artist(*args):
+ import jamaendo
+ from showartist import ShowArtist
+ track = self.playlist.current()
+ artist = jamaendo.get_artist(int(track.artist_id))
+ wnd = ShowArtist(artist)
+ wnd.show_all()
+ def to_album(*args):
+ import jamaendo
+ from showalbum import ShowAlbum
+ track = self.playlist.current()
+ album = jamaendo.get_album(int(track.album_id))
+ wnd = ShowAlbum(album)
+ wnd.show_all()
+
+ b = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ b.set_label("Artist")
+ b.connect("clicked", to_artist)
+ self.menu.append(b)
+
+ b = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ b.set_label("Album")
+ b.connect("clicked", to_album)
+ self.menu.append(b)
+
+ self.menu.show_all()
+ self.set_app_menu(self.menu)
+
+ def on_state_changed(self, *args):
self.update_state()
self.update_play_button()
+ if self.player.playing():
+ self.start_position_timer()
+ else:
+ self.stop_position_timer()
+
+
def get_album_id(self):
- if self.playlist and self.playlist.current_index() > -1:
- return self.playlist.current().album_id
+ if self.player.playlist and self.player.playlist.current():
+ c = self.player.playlist.current()
+ if not c.album_id:
+ c.load()
+ if c.album_id:
+ return c.album_id
return None
def on_destroy(self, wnd):
self.stop_position_timer()
- postoffice.disconnect('album-cover', self)
+ postoffice.disconnect(['album-cover', 'next', 'prev', 'play', 'stop'], self)
def add_stock_button(self, btns, stock, cb):
btn = hildon.GtkButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
self.playbtn.set_data('state', 'play')
def set_labels(self, track, artist, album, playlist_pos, playlist_size):
- self.playlist_pos.set_markup('<span size="small">%s/%s songs</span>'%(playlist_pos, playlist_size))
- self.track.set_markup('<span size="x-large">%s</span>'%(track))
- self.artist.set_markup('<span size="large">%s</span>'%(artist))
- self.album.set_markup('<span foreground="#aaaaaa">%s</span>'%(album))
+ self.playlist_pos.set_markup('<span size="small">Track %s of %s</span>'%(int(playlist_pos)+1, playlist_size))
+ self.track.set_markup('<span size="x-large">%s</span>'%(cgi.escape(track)))
+ self.artist.set_markup('<span size="large">%s</span>'%(cgi.escape(artist)))
+ self.album.set_markup('<span foreground="#aaaaaa">%s</span>'%(cgi.escape(album)))
def volume_changed_hildon(self, widget):
self._position_timer = None
def clear_position(self):
- self.progress.set_value(0)
+ self.progress.set_position(0)
def set_song_position(self, time_elapsed, total_time):
value = (float(time_elapsed) / float(total_time)) if total_time else 0
- self.progress.set_value( value )
+ self.progress.set_position(value)
def update_state(self):
item = self.playlist.current()
if item:
if not item.name:
item.load()
- #print "current:", item
self.set_labels(item.name, item.artist_name, item.album_name,
self.playlist.current_index(), self.playlist.size())
postoffice.notify('request-album-cover', int(item.album_id), 300)
- #jamaendo.get_album_cover_async(album_cover_receiver, int(item.album_id), size=200)
- #coverfile = jamaendo.get_album_cover(int(item.album_id), size=200)
- #print "coverfile:", coverfile
- #self.cover.set_from_file(coverfile)
+ else:
+ self.set_labels('', '', '', 0, 0)
+ tmp = util.find_resource('album.png')
+ if tmp:
+ self.cover.set_from_file(tmp)
def set_album_cover(self, albumid, size, cover):
if size == 300:
playing = self.get_album_id()
- if int(playing) == int(albumid):
+ if playing and albumid and (int(playing) == int(albumid)):
self.cover.set_from_file(cover)
def play_tracks(self, tracks):
- self.stop_position_timer()
self.clear_position()
self.playlist = Playlist(tracks)
self.player.stop()
self.player.play(self.playlist)
- self.update_state()
- self.update_play_button()
def on_play(self, button):
if not self.player.playing():
self.player.play(self.playlist)
- self.start_position_timer()
- self.update_state()
- self.update_play_button()
else:
- self.stop_position_timer()
self.player.pause()
- self.update_state()
- self.update_play_button()
def on_prev(self, button):
self.player.prev()
- self.update_state()
+
def on_next(self, button):
self.player.next()
- self.update_state()
+
def on_stop(self, button):
- self.stop_position_timer()
self.clear_position()
self.player.stop()
- self.update_play_button()
def open_playerwindow():
player = PlayerWindow()
def notify(self, tag, *data):
clients = self.tags.get(tag)
if clients:
- #log.debug("(%s %s) -> [%s]",
- # tag,
- # " ".join(str(x) for x in data),
- # " ".join(repr(x) for x,_ in clients))
for ref, client in clients:
client(*data)
def connect(self, tag, ref, callback):
- if tag not in self.tags:
- self.tags[tag] = []
- clients = self.tags[tag]
- if callback not in clients:
- clients.append((ref, callback))
+ if not isinstance(tag, list):
+ tag = [tag]
+ for t in tag:
+ if t not in self.tags:
+ self.tags[t] = []
+ clients = self.tags[t]
+ if callback not in clients:
+ clients.append((ref, callback))
def disconnect(self, tag, ref):
- if tag not in self.tags:
- self.tags[tag] = []
- self.tags[tag] = [(_ref, cb) for _ref, cb in self.tags[tag] if _ref != ref]
+ if not isinstance(tag, list):
+ tag = [tag]
+ for t in tag:
+ if t not in self.tags:
+ self.tags[t] = []
+ self.tags[t] = [(_ref, cb) for _ref, cb in self.tags[t] if _ref != ref]
postoffice = PostOffice()
import hildon
import jamaendo
from playerwindow import open_playerwindow
+from albumlist import RadioList
class RadiosWindow(hildon.StackableWindow):
def __init__(self):
# Results list
self.panarea = hildon.PannableArea()
- self.result_store = gtk.ListStore(str, int)
- #self.result_store.append(['red'])
- self.result_view = gtk.TreeView(self.result_store)
- col = gtk.TreeViewColumn('Name')
- self.result_view.append_column(col)
- cell = gtk.CellRendererText()
- col.pack_start(cell, True)
- col.add_attribute(cell, 'text', 0)
- self.result_view.set_search_column(0)
- col.set_sort_column_id(0)
- self.result_view.connect('row-activated', self.row_activated)
+ self.radiolist = RadioList()
+ self.radiolist.connect('row-activated', self.row_activated)
- self.panarea.add(self.result_view)
+ self.panarea.add(self.radiolist)
self.radios = {}
hildon.hildon_gtk_window_set_progress_indicator(self, 1)
for item in jamaendo.starred_radios():
self.radios[item.ID] = item
- self.result_store.append([self.radio_text(item), item.ID])
+ self.radiolist.add_radio(item)
hildon.hildon_gtk_window_set_progress_indicator(self, 0)
self.add(self.panarea)
- def radio_text(self, radio):
- if radio.name and radio.idstr:
- return "%s (%s)" % (radio.name, radio.idstr)
- elif radio.name:
- return radio.name
- elif radio.idstr:
- return radio.idstr
- else:
- return "Radio #%s" % (radio.ID)
-
def make_button(self, text, subtext, callback):
button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT,
hildon.BUTTON_ARRANGEMENT_VERTICAL)
if callback:
button.connect('clicked', callback)
- #image = gtk.image_new_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON)
- #button.set_image(image)
- #button.set_image_position(gtk.POS_RIGHT)
-
return button
def row_activated(self, treeview, path, view_column):
- treeiter = self.result_store.get_iter(path)
- title, _id = self.result_store.get(treeiter, 0, 1)
+ _id = self.radiolist.get_radio_id(path)
item = self.radios[_id]
- #print _id, item
self.open_item(item)
def open_item(self, item):
self.create_menu()
def create_menu(self):
- def on_player():
+ def on_player(*args):
from playerwindow import open_playerwindow
open_playerwindow()
self.menu = hildon.AppMenu()
class Settings(object):
defaults = {
- 'volume':0.5,
+ 'volume':0.1,
'user':None,
'favorites':set([]) # local favorites - until we can sync back
}
# (based on http://pygstdocs.berlios.de/pygst-tutorial/seeking.html)
#
import gtk
+import cgi
import hildon
import jamaendo
from playerwindow import open_playerwindow
vbox2 = gtk.VBox()
self.albumname = gtk.Label()
- self.albumname.set_markup('<big>%s</big>'%(album.name))
+ self.albumname.set_markup('<big>%s</big>'%(cgi.escape(album.name)))
self.trackarea = hildon.PannableArea()
self.tracks = TrackList(numbers=True)
self.create_menu()
- self.show_all()
-
def create_menu(self):
- def on_player():
+ def on_player(*args):
from playerwindow import open_playerwindow
open_playerwindow()
self.menu = hildon.AppMenu()
def row_activated(self, treeview, path, view_column):
_id = self.tracks.get_track_id(path)
- log.debug("clicked %s", _id)
+ track = jamaendo.get_track(_id)
+ self.open_item(track)
def open_item(self, item):
if isinstance(item, jamaendo.Album):
--- /dev/null
+import logging
+import gtk
+import cairo
+
+log = logging.getLogger(__name__)
+
+# shows the current song position (looking a bit nicer than a default widget, hopefully)
+class SongPosition(gtk.DrawingArea):
+ WIDTH = 8.0
+ HEIGHT = 8.0
+
+ def __init__(self):
+ gtk.DrawingArea.__init__(self)
+ self.connect('expose-event', self.on_expose)
+ self.set_size_request(24, 8)
+ self.pos = 0.0
+
+ orange0 = self.hex_to_flt(0xec, 0xac, 0x1f)
+ orange1 = self.hex_to_flt(0xea, 0x86, 0x1d, 0.25)
+ purple0 = self.hex_to_flt(0x81, 0x3e, 0x82)
+ purple1 = self.hex_to_flt(0x56, 0x2d, 0x5a, 0.25)
+
+ lightclr = cairo.LinearGradient(0.0, 0.0, 0.0, self.HEIGHT)
+ lightclr.add_color_stop_rgba(0.0, *purple1)
+ lightclr.add_color_stop_rgba(1.0, *purple0)
+
+ darkclr = cairo.LinearGradient(0.0, 0.0, 0.0, self.HEIGHT)
+ darkclr.add_color_stop_rgba(0.0, 0.0, 0.0, 0.0, 0.0)
+ darkclr.add_color_stop_rgba(1.0, 0.25, 0.25, 0.25, 1.0)
+
+ markerclr = cairo.LinearGradient(0.0, 0.0, 0.0, self.HEIGHT)
+ markerclr.add_color_stop_rgba(0.0, *orange1)
+ markerclr.add_color_stop_rgba(0.5, *orange0)
+ markerclr.add_color_stop_rgba(1.0, *orange0)
+
+ self.lightclr = lightclr
+ self.darkclr = darkclr
+ self.markerclr = markerclr
+
+ def on_expose(self, widget, event):
+ context = self.window.cairo_create()
+ context.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+ context.clip()
+ self.draw(context)
+ return True
+
+ #ecac1f - light orange
+ #ea861d - dark orange
+
+ #813e82 - light purple
+ #562d5a - dark purple
+
+ def hex_to_flt(self, r, g, b, a = 255.0):
+ return float(r)/255.0, float(g)/255.0, float(b)/255.0, float(a)/255.0
+
+ def draw(self, context):
+ rect = self.get_allocation()
+
+
+ #context.set_source_rgb(1.0, 0.5, 0.0)
+ lowx = rect.width*self.pos - self.WIDTH*0.5
+ hix = rect.width*self.pos + self.WIDTH*0.5
+
+ if lowx < 0.0:
+ lowx = 0.0
+ hix = self.WIDTH
+ elif hix > rect.width:
+ lowx = rect.width - self.WIDTH
+ hix = rect.width
+
+ if lowx > 0.01:
+ context.rectangle(0, 0, lowx, rect.height)
+ context.set_source(self.lightclr)
+ context.fill()
+
+ if hix < rect.width-0.01:
+ context.rectangle(hix, 0, rect.width-hix, rect.height)
+ context.set_source(self.darkclr)
+ context.fill()
+
+ context.rectangle(lowx, 0, self.WIDTH, rect.height)
+ context.set_source(self.markerclr)
+ context.fill()
+
+ def set_position(self, pos):
+ assert 0 <= pos <= 1
+ self.pos = pos
+ self.invalidate()
+
+ def invalidate(self):
+ self.queue_draw()